iOS Developer动画相关

仿高德路线规划滑动效果

2019-04-03  本文已影响0人  果哥爸

因为项目有个界面要模仿高德地图路径规划滑动效果,因此写了demo,并简单说下分析过程。

高德地图效果演示:

仿高德路线规划滑动.gif

demo效果演示:

高德地图规划滑动.gif

Demo地址:https://github.com/fangjinfeng/MySampleCode/tree/master/FJFBlogProjectDemo

一. 分析

二.代码分析:

// 当有 多个手势 都可以 响应
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

    return YES;
}

来支持响应多个手势。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.tableView.frame.origin.y > _scrollViewStartPositionY) {
        [scrollView setContentOffset:CGPointMake(0, 0)];
    }
}

这里的_scrollViewStartPositionY是顶部指定位置。

#pragma mark - 手势处理
- (void)handlePanGesture:(UIPanGestureRecognizer *)sender {
    
    if (sender.state == UIGestureRecognizerStateBegan) {
        
        _beganPoint = [sender locationInView:sender.view.superview];
        _curPoint = sender.view.center;
        _topTipContainerViewCurrentY = _topContainerView.frame.origin.y;
        _previousOffsetY = self.tableView.contentOffset.y;
        
    } else if(sender.state == UIGestureRecognizerStateChanged) {
        
        CGPoint point = [sender locationInView:sender.view.superview];
        
        CGFloat offsetY = _previousOffsetY - self.tableView.contentOffset.y;
        NSInteger y_offset = point.y - _beganPoint.y - offsetY;
        
        if (sender.view.frame.origin.y >= _scrollViewStartPositionY || (self.tableView.contentOffset.y == 0 && self.tableView.contentSize.height > self.tableView.frame.size.height)) {
            sender.view.center = CGPointMake(_curPoint.x, _curPoint.y + y_offset);
            [self updateViewControlsWithSlideOffset:y_offset];
        }
        
        if (sender.view.frame.origin.y > _scrollViewLimitMaxY) {
            sender.view.y = _scrollViewLimitMaxY;
            [self updateViewControlsWithSlideUp:NO];
        }
        else if(sender.view.frame.origin.y < _scrollViewStartPositionY) {
            
            sender.view.y = _scrollViewStartPositionY;
             [self updateViewControlsWithSlideUp:YES];
        }
    } else if(sender.state == UIGestureRecognizerStateEnded) {
        
        if (sender.view.frame.origin.y <= _scrollViewStartPositionY || sender.view.frame.origin.y > _scrollViewLimitMaxY) {
            if (sender.view.frame.origin.y <= _scrollViewStartPositionY) {
                [self updateViewControlsWithSlideUp:YES];
            }
            if (sender.view.frame.origin.y > _scrollViewLimitMaxY) {
                [self updateViewControlsWithSlideUp:NO];
            }
            return;
        }
        // 滑动速度处理
        CGPoint velocity = [sender velocityInView:self.view];
        CGFloat speed = 350;
        if (velocity.y < - speed) {
            // 快速向上
            [self tableViewMoveToTop];
            return;
        } else if (velocity.y > speed) {
            // 快速向下
            [self tableViewMoveToBottom];
            return;
        }
        
        // 滑动临界值
        CGFloat criticalValue = _scrollViewLimitMaxY/2.0;
        if (sender.view.frame.origin.y <= criticalValue) {
            [self tableViewMoveToTop];
        } else {
            [self tableViewMoveToBottom];
        }
    }
}

这里几个点需要注意:

  1. _beganPoint、_curPoint两个参数是用来计算手势滑动距离然后调整scrollView滑动距离。而_previousOffsetY是用来记录滑动之前tableView的内部视图的偏移距离,因为当tableView滑动到顶部指定位置后,tableView开始滚动,这时候tableView向下滑动是先移动了tableView内部的滚动距离,然后才是滑动距离,因此需要将这部分值先记录,然后去除掉,才是tableView向下真正需要滑动的距离。
 CGFloat offsetY = _previousOffsetY - self.tableView.contentOffset.y;
 NSInteger y_offset = point.y - _beganPoint.y - offsetY;

2.滑动过程中,顶部视图的移动和渐变处理,这里先依据滑动的距离算出tableView滑动距离tableView最大滑动距离比值,然后再算出顶部视图需要移动的距离和背景的透明度

- (void)updateViewControlsWhenSliding {
    if (self.tableView.frame.origin.y > _scrollViewStartPositionY && self.tableView.frame.origin.y < _scrollViewLimitMaxY) {
        
        CGFloat offsetLimitDistance = _scrollViewLimitMaxY - _scrollViewStartPositionY;
        CGFloat offsetDistance = self.tableView.frame.origin.y - _scrollViewStartPositionY;
        if (offsetDistance > 0 && offsetDistance < offsetLimitDistance) {
            CGFloat topViewHeight = [FJFTopContainerView viewHeight];
            CGFloat topViewHeightOffset =  offsetDistance * (topViewHeight / offsetLimitDistance);
            CGFloat viewAlpha = offsetDistance / offsetLimitDistance;
            _topContainerView.y = topViewHeightOffset - topViewHeight;
            _topContainerView.alpha = viewAlpha;       
         }
    }
}

3.滑动速度处理,依据velocityInView函数获取速度值,然后依据当前速度值大小正负设定的速度值比较来判断是否需要向上或向下移动

 // 滑动速度处理
CGPoint velocity = [sender velocityInView:self.view];
CGFloat speed = 350;
if (velocity.y < - speed) {
     // 快速向上
      [self tableViewMoveToTop];
      return;
} else if (velocity.y > speed) {
    // 快速向下
    [self tableViewMoveToBottom];
    return;
 }

4.滑动临界值处理,判断最后滑动位置与底部指定位置一半,两个值的大小来判断滑动的方向。

 // 滑动临界值
CGFloat criticalValue = _scrollViewLimitMaxY/2.0;
if (sender.view.frame.origin.y <= criticalValue) {
    [self tableViewMoveToTop];
} else {
    [self tableViewMoveToBottom];
 }

三.总结

这里最主要就是介绍了分析的思路,来找出可靠的实现方法,具体逻辑,详见demo

上一篇下一篇

猜你喜欢

热点阅读