我正在为iOS寻找类似AndroidSlidingUpPanel的内容。我找到了MBPullDownController,但它需要使用两个ViewControllers,并且需要对我正在实施的应用程序的架构进行重大更改。
我只想在现有的视图控制器中添加子视图。我该怎么做呢?
答案 0 :(得分:6)
我在我的iOS应用程序中使用了向上滑动面板,我发现诀窍是将自定义视图添加到故事板(或xib文件)中的视图控制器,但设置其框架以便它不在屏幕上。您可以使用layout constraints确保视图在任何设备上都不在屏幕上。
然后,它只是在适当的时候在屏幕上设置动画的动画。 e.g:
- (IBAction)showPanel:(id)sender
{
// panelShown is an iVar to track the panel state...
if (!panelShown) {
// myConstraint is an IBOutlet to the appropriate constraint...
// Use this method for iOS 8+ otherwise use a frame based animation...
myConstraint.constant -= customView.frame.size.height;
[UIView animateWithDuration:0.5 animations:^{
[self.view setNeedsLayout];
}];
}
else {
myConstraint.constant += customView.frame.size.height;
[UIView animateWithDuration:0.5 animations:^{
[self.view setNeedsLayout];
}];
}
}
如果您只想向上/向下滑动并显示面板,则可以使用UISwipeGestureRecognizer
,如下所示:
- (void)viewDidLoad
{
[super viewDidLoad];
// iVar
swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(didSwipe:)];
swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeUp];
// Do the same again with swipeDown using UISwipeGestureRecognizerDirectionDown...
}
- (void)didSwipe:(UIGestureRecognizer *)swipe
{
if (swipe == swipeUp) {
// Show panel (see above)...
} else {
// Hide panel (see above)...
}
}
如果您希望面板像打开控制中心一样跟踪您的手指,那么您可以使用UIPanGestureRecognizer
并获取translationInView:
和velocityInView:
并相应地调整面板。以下是跟踪手指移动的代码片段,但使用touchesBegan:withEvent:
中的- (void)touchesMoved:withEvent:
- (void)touchesEnded:withEvent:
和UIViewController
方法让您体验:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Don't worry too much about buttonView this is another view that I animate upwards to get out the way of the panel as it slides in from the left...
[super touchesBegan:touches withEvent:event];
CGPoint loc = [[touches anyObject] locationInView:self.view];
// Save last touch for reference...
lastTouch = loc;
// leftBeginRect is an area where the user can start to drag the panel...
// trackFinger defines whether the panel should move with the users gestures or not...
if (CGRectContainsPoint(leftBeginRect, loc) && canTrack) {
trackFinger = YES;
}
// Left view is a reference to the panel...
else if (leftView.frame.size.width >= 300) {
// This means that the panel is shown and therefore should track the user's finger back towards the edge of the screen...
CGRect frame = CGRectMake(250, 0, 100, self.view.frame.size.height);
if (CGRectContainsPoint(frame, loc) && canTrack) {
trackFinger = YES;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
CGPoint loc = [[touches anyObject] locationInView:self.view];
// Need to work out the direction in which the user is panning...
if (lastTouch.x > loc.x) {
currentFingerDirection = RHFingerDirectionLeft;
}
else {
currentFingerDirection = RHFingerDirectionRight;
}
lastTouch = loc;
if (trackFinger) {
if (loc.x <= 300) {
// This means that the panel is somewhere between fully exposed and closed...
// This is where the frame for the left view (and the constraints) are adjusted according to the user's current finger position...
CGRect frame = leftView.frame;
frame.size.width = loc.x;
[leftView setFrame:frame];
leftViewConstraint.constant = loc.x;
if (loc.x <= 80) {
float percentage = loc.x / 80;
int amount = 100 * percentage;
CGRect otherFrame = buttonView.frame;
otherFrame.origin.y = -amount;
[buttonView setFrame:otherFrame];
constraint.constant = constraintConstant + amount;
}
}
else {
CGRect frame = leftView.frame;
frame.size.width = 300;
[leftView setFrame:frame];
leftViewConstraint.constant = 300;
frame = buttonView.frame;
frame.origin.y = -100;
[buttonView setFrame:frame];
constraint.constant = constraintConstant + 100;
trackFinger = NO;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// This method works out if the panel should pop open or spring closed when the user ends the gesture...
[super touchesEnded:touches withEvent:event];
if (trackFinger) {
CGPoint loc = [[touches anyObject] locationInView:self.view];
if (loc.x >= 50 && currentFingerDirection == RHFingerDirectionRight) {
CGRect frame = leftView.frame;
frame.size.width = 300;
leftViewConstraint.constant = 300;
CGRect otherFrame = buttonView.frame;
otherFrame.origin.y = -100;
constraint.constant = constraintConstant + 100;
[UIView animateWithDuration:0.2 animations:^{
[leftView setFrame:frame];
[buttonView setFrame:otherFrame];
}];
}
else if (loc.x <= 250 && currentFingerDirection == RHFingerDirectionLeft) {
CGRect frame = leftView.frame;
frame.size.width = 0;
leftViewConstraint.constant = 0;
CGRect otherFrame = buttonView.frame;
otherFrame.origin.y = 0;
constraint.constant = constraintConstant;
[UIView animateWithDuration:0.2 animations:^{
[leftView setFrame:frame];
[buttonView setFrame:otherFrame];
}];
}
else if (loc.x <= 150) {
CGRect frame = leftView.frame;
frame.size.width = 0;
leftViewConstraint.constant = 0;
CGRect otherFrame = buttonView.frame;
otherFrame.origin.y = 0;
constraint.constant = constraintConstant;
[UIView animateWithDuration:0.2 animations:^{
[leftView setFrame:frame];
[buttonView setFrame:otherFrame];
}];
}
else {
CGRect frame = leftView.frame;
frame.size.width = 300;
leftViewConstraint.constant = 300;
CGRect otherFrame = buttonView.frame;
otherFrame.origin.y = -100;
constraint.constant = constraintConstant + 100;
[UIView animateWithDuration:0.2 animations:^{
[leftView setFrame:frame];
[buttonView setFrame:otherFrame];
}];
}
trackFinger = NO;
}
currentFingerDirection = RHFingerDirectionNone;
}
代码非常复杂,但它会产生一个漂亮的面板动画,就像控制中心一样跟随你的手指。
答案 1 :(得分:3)
很抱歉迟到了回复。我根据Rob的答案创建了一个小型的lib。 https://github.com/hoomazoid/CTSlidingUpPanel
使用起来非常简单:
@IBOutlet weak var bottomView: UIView!
var bottomController:CTBottomSlideController?;
override func viewDidLoad() {
super.viewDidLoad()
//You can provide nil to tabController and navigationController
bottomController = CTBottomSlideController(parent: view, bottomView: bottomView,
tabController: self.tabBarController!,
navController: self.navigationController, visibleHeight: 64)
//0 is bottom and 1 is top. 0.5 would be center
bottomController?.setAnchorPoint(anchor: 0.7)
}