如何制作像谷歌地图应用程序一样的向上滑动面板?

swa*_*lla 7 objective-c ios

我正在寻找像iOS版AndroidSlidingUpPanel这样的东西.我找到了MBPullDownController,但它需要使用两个ViewControllers,并且需要对我正在实现的应用程序的体系结构进行大的更改.

我只想在现有的视图控制器中添加子视图.我该怎么做呢?

Rob*_*ers 8

我在我的iOS应用程序中使用了相当多的滑动面板,我发现诀窍是将自定义视图添加到故事板(或xib文件)中的视图控制器,但设置其框架以使其不在屏幕上.您可以使用布局约束确保视图在任何设备上保持屏幕状态.

然后,这只是在适当的时候在屏幕上设置动画的动画.例如:

- (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];
        }];
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您只想向上/向下滑动并显示面板,您可以这样使用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)...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想面板跟踪你的手指,当你打开控制中心一样,那么你就可以使用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;
}
Run Code Online (Sandbox Code Playgroud)

代码非常复杂,但它会产生一个漂亮的面板动画,就像控制中心一样.

  • 如果有人感兴趣,我的类似示例项目:https://github.com/rshev/Example_PanelBottom (2认同)