iOS控件中心般的滑动视图实现

时间:2016-01-03 15:36:29

标签: ios objective-c swift uiview user-experience

我尝试使用Objective-C在我的应用中实现iOS风格的控制中心 - 实际上,如果用户选择的话,我希望在现有视图上有一个向下滑动的视图。在默认情况下,较低的视图(即视图下方)应该是可见的。

我已经看了一下,并且已经实施了一个粗略的实现,利用this YouTube视频中的Swift代码 - 但仍然发现难以完成此操作。还有一个基于本教程的Git项目(DragSlideView),但我似乎在运行时遇到了除教程/ Git项目(在Swift中)中显示的其他问题。感谢大家能指出我在这里做错了什么......

代码粘贴在下面(以及正在发生的事情的屏幕截图)。

总之,问题在于,当我开始滑动/向下拖动视图时,一个非常慢而且没有“快速”和两个,它往往会水平偏离外面屏幕。

感谢您的投入!

ViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"ControlCenterView" owner:self options:nil];
    self.resultsView = [nibContents lastObject];

//    self.resultsView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    [self.controlCenterView setFrame:CGRectMake(0, 
    0 + self.navigationController.navigationBar.bounds.size.height + 20 - (self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 20 - TOOLBAR_HEIGHT), 
    self.view.bounds.size.width, 
    (self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 20 - TOOLBAR_HEIGHT))];    // 20 is the height of the thin section above the navigation bar on the screen.

    [self.view addSubview:self.controlCenterView];
    [self.controlCenterView setupView];
}

ControlCenterView.m:

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];

    self.backgroundColor = [UIColor greenColor];    // Testing...

//    [self setFrame:self.bounds];
//    self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;

    return self;
}

- (void)setupView
{
    if (self) {
        self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
        self.panGestureRecognizer.cancelsTouchesInView = NO;
        [self.panGestureRecognizer setDelegate:self];   // Need for this TBC?
        [self addGestureRecognizer:self.panGestureRecognizer];

        self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
        self.animator.delegate = self;      // Need for this TBC?

        self.dynamicItem = [[UIDynamicItemBehavior alloc] initWithItems:@[self]];
        self.dynamicItem.allowsRotation = NO;
        self.dynamicItem.elasticity = 0.3;

        CGPoint snapPoint = {self.superview.frame.size.width / 2, -self.superview.frame.size.height / 2};
        self.snap = [[UISnapBehavior alloc] initWithItem:self snapToPoint:snapPoint];
        [self.animator addBehavior:self.snap];

        self.gravity = [[UIGravityBehavior alloc] initWithItems:@[self]];
        self.gravity.gravityDirection = CGVectorMake(0, -1);

        self.container = [[UICollisionBehavior alloc] initWithItems:@[self]];
        // self.container.translatesReferenceBoundsIntoBoundary = YES;

        [self configureContainer];

        [self.animator addBehavior:self.gravity];
        [self.animator addBehavior:self.dynamicItem];
        [self.animator addBehavior:self.container];
    }
}

- (void)configureContainer
{
//    CGFloat boundaryWidth = self.bounds.size.width;
//    CGFloat boundaryHeight = self.bounds.size.height;

    CGFloat boundaryWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat boundaryHeight = [UIScreen mainScreen].bounds.size.height - TOOLBAR_HEIGHT;    // TOOLBAR_HEIGHT is 48.

    [self.container addBoundaryWithIdentifier:@"upper" fromPoint:CGPointMake(0, -self.frame.size.height + 64 + 5) toPoint:CGPointMake(boundaryWidth, -self.frame.size.height + 64 + 30)];    // 64 is the height of the navigation bar + the height of the thin section above it on the screen (thus 44 + 20). 30 is the distance constraint between the bottom of the grey handle and the bottom of the controlCenterView.
    [self.container addBoundaryWithIdentifier:@"lower" fromPoint:CGPointMake(0, boundaryHeight) toPoint:CGPointMake(boundaryWidth, boundaryHeight)];

//    [self.container addBoundaryWithIdentifier:@"left" fromPoint:CGPointMake(0, -self.frame.size.height + 64 + 5) toPoint:CGPointMake(0, boundaryHeight)];
//    [self.container addBoundaryWithIdentifier:@"right" fromPoint:CGPointMake(boundaryWidth, -self.frame.size.height + 64 + 30) toPoint:CGPointMake(boundaryWidth, boundaryHeight)];
}

- (IBAction)handlePan:(id)sender
{
    CGFloat velocity = [sender velocityInView:self.superview].y;
    CGRect movement = self.frame;
    movement.origin.x = ORIGIN_X;
    movement.origin.y = movement.origin.y + (velocity * 0.05);

    if ([sender state] == UIGestureRecognizerStateEnded) {
        [self panGestureEnded];
    }
    else if ([sender state] == UIGestureRecognizerStateBegan) {
        [self snapToBottom];
    }
    else {
        [self.animator removeBehavior:self.snap];
        self.snap = [[UISnapBehavior alloc] initWithItem:self snapToPoint:CGPointMake(CGRectGetMidX(movement), CGRectGetMidY(movement))];
        [self.animator addBehavior:self.snap];
    }
}

- (void)panGestureEnded
{
    [self.animator removeBehavior:self.snap];

    CGPoint velocity = [self.dynamicItem linearVelocityForItem:self];

    if (fabsf(velocity.y) > 250) {
        if (velocity.y < 0) {
            [self snapToTop];
        }
        else {
            [self snapToBottom];
        }
    }
    else {
        CGFloat superViewHeight = self.superview.bounds.size.height;
        if (superViewHeight) {
            if (self.frame.origin.y > superViewHeight / 2) {
                [self snapToBottom];
            }
            else {
                [self snapToTop];
            }
        }
    }
}

- (void)snapToBottom
{
    self.gravity.gravityDirection = CGVectorMake(0, 2.5);
}

- (void)snapToTop
{
    self.gravity.gravityDirection = CGVectorMake(0, -2.5);
}

enter image description here

0 个答案:

没有答案