平移/可滑动视图,如相机锁定屏幕

cho*_*ise 2 animation objective-c uiview uigesturerecognizer ios

每个人都知道相机锁屏中的可拖动视图

在此输入图像描述

我想要类似的东西.我的布局看起来像这样

在此输入图像描述

  • 此子视图应从底部拖动,并应在cetrain高度保持打开状态.
  • 当快速向上滑动时,它应该在向上拖动子视图时打开,但在最大位置之前停止,如果向上滑动然后向下滑动它应该向下滑动
  • 它也可以自行消失
  • 点击时应自行向上/向下滑动

你可以在锁定屏幕上看到这种行为非常好(除了高度停止).我尝试了不同的东西UIPanGestureRecognizer,然后设置最大值,但后来我无法滑动.

在UIKit有预先包装的东西还是我自己做的.如果没有,这种行为会有什么好处?

isa*_*aac 6

这是计划:你将继续UIView的子类.您将添加一些属性并覆盖一些方法.这个想法是你让手指用touchesBegan和touchesMoved来决定运动.当手指抬起触摸时,您可以将视图设置为合适的静止位置.在我提供的代码示例中,这将是完全扩展或完全缩回,但如果您愿意,可以随时撤消.

听起来你想要应用一些惯性.这稍微复杂一点,因为你必须自己添加一个额外的动画 - 但是,你只需要插入正确的动画(例如,让它通过结束点动画,然后使用计时功能返回)并且在用户完成移动后它会激活.如果你想要花哨,你可以跟踪滑动的速度并根据这个速度/动量来发射动画.

以下是一个代码示例,可帮助抽屉进出动画.它没有你所描述的那种幻想,但它应该为你提供一个基础来弄清楚如何以及在何处引入这种行为.

你的班级需要一些属性/ ivars:一个"当前点",一个原点,一个天花板(视图应该停止向上拖动的点,或者它在"out"中停留的位置)和一个楼层(最大y偏移量) ,或它不会在下面的坐标).

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *touch = [touches anyObject];
    CGPoint startPt = [touch locationInView:self];
    self.currentPoint = startPt;

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    CGPoint activePoint = [[touches anyObject] locationInView:self];

    //new position
    CGPoint newPoint = CGPointMake(self.center.x,
                                   self.center.y + (activePoint.y - currentPoint.y));

    if (newPoint.y > self.draggingFloor) {
        //too low
        newPoint.y = self.draggingFloor;

    } else if (newPoint.y < self.draggingCeiling) {
        //too high
        newPoint.y = self.draggingCeiling;
    }

    self.center = newPoint;

}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    //The user isn't touching. Now we can adjust to drawer to a "better" position.
    //The 150f here is going to depend on how far the view should be dragged before it opens.
    CGFloat median = pullDrawerYOrigin + 150.0f;
    CGFloat position = self.center.y;

    if (position <= median) {
        //We're closer to open than closed. So open all the way. 
        [self animateDrawerToPositionYesForOpen:YES];
    }

    else if (position >= median)  {
        //close
        [self animateDrawerToPositionYesForOpen:NO];
    }


}

- (CGFloat) draggingFloor {

    //Don't drag any lower than this.
    if (!__draggingFloor) {
        __draggingFloor = pullDrawerYOrigin + (self.bounds.size.height *.5);
    }

    return __draggingFloor;
}

- (CGFloat) draggingCeiling {

    //Don't drag any higher than this.
    if (!__draggingCeiling) {
        __draggingCeiling = self.superview.bounds.size.height + (self.bounds.size.height * .05);
    }

    return __draggingCeiling;

}
- (void) animateDrawerToPositionYesForOpen:(BOOL)position {

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    [UIView setAnimationDuration:.2];

    CGPoint myCenter = self.center;

    if (position == YES) {
        myCenter.y = self.draggingCeiling;
    }

    else if (position == NO) {
        myCenter.y = self.draggingFloor;
    }

    self.center = myCenter;

    [UIView commitAnimations];

}
Run Code Online (Sandbox Code Playgroud)