iOS 给view加一个拖拽功能

作者: codychen123 | 来源:发表于2017-09-17 13:24 被阅读190次

    前言

    现在的直播app都具有悬浮窗功能,悬浮窗可以拖拽,并且具有回弹动画,可以设计一个UIView的分类实现,减少侵入性。

    主要代码及思路

    思路

    • 给view添加一个pan的手势,在gesture的状态中进行判断(例如边界的回弹),最终拖拽手势结束时,通过block把手势回调出去。

    代码

    #import "UIView+dragable.h"
    #import <objc/runtime.h>
    
    #define ScreenWidth                         [[UIScreen mainScreen] bounds].size.width
    #define ScreenHeight                        [[UIScreen mainScreen] bounds].size.height
    
    static const char *ActionHandlerPanGestureKey;
    
    @implementation UIView (dragable)
    
    - (void)addDragableActionWithEnd:(void (^)(CGRect endFrame))endBlock; {
        // 添加拖拽手势
        UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanAction:)];
        [self addGestureRecognizer:panGestureRecognizer];
        
        // 记录block
        objc_setAssociatedObject(self, ActionHandlerPanGestureKey, endBlock, OBJC_ASSOCIATION_COPY);
    }
    
    @end
    
    
    • 由于在uiview的分类中,所以使用了runtime关联一下需要回调的block
    - (void)handlePanAction:(UIPanGestureRecognizer *)sender {
        CGPoint point = [sender translationInView:[sender.view superview]];
        
        CGFloat senderHalfViewWidth = sender.view.frame.size.width / 2;
        CGFloat senderHalfViewHeight = sender.view.frame.size.height / 2;
        
        __block CGPoint viewCenter = CGPointMake(sender.view.center.x + point.x, sender.view.center.y + point.y);
        // 拖拽状态结束
        if (sender.state == UIGestureRecognizerStateEnded) {
            [UIView animateWithDuration:0.4 animations:^{
                if ((sender.view.center.x + point.x - senderHalfViewWidth) <= 12) {
                    viewCenter.x = senderHalfViewWidth + 12;
                }
                if ((sender.view.center.x + point.x + senderHalfViewWidth) >= (ScreenWidth - 12)) {
                    viewCenter.x = ScreenWidth - senderHalfViewWidth - 12;
                }
                if ((sender.view.center.y + point.y - senderHalfViewHeight) <= 12) {
                    viewCenter.y = senderHalfViewHeight + 12;
                }
                if ((sender.view.center.y + point.y + senderHalfViewHeight) >= (ScreenHeight - 12)) {
                    viewCenter.y = ScreenHeight - senderHalfViewHeight - 12;
                }
                sender.view.center = viewCenter;
            } completion:^(BOOL finished) {
                void (^endBlock)(CGRect endFrame) = objc_getAssociatedObject(self, ActionHandlerPanGestureKey);
                if (endBlock) {
                    endBlock(sender.view.frame);
                }
            }];
            [sender setTranslation:CGPointMake(0, 0) inView:[sender.view superview]];
        } else {
            // UIGestureRecognizerStateBegan || UIGestureRecognizerStateChanged
            viewCenter.x = sender.view.center.x + point.x;
            viewCenter.y = sender.view.center.y + point.y;
            sender.view.center = viewCenter;
            [sender setTranslation:CGPointMake(0, 0) inView:[sender.view superview]];
        }
    }
    
    • UIGestureRecognizerState有个状态是UIGestureRecognizerStateEnded,当拖拽结束时,需要判断拖拽视图的位置是否超出屏幕边界,如果超出边界,需要回弹到边界内。
    • 回弹动画结束后,用runtime取出关联的block,把最终的视图的frame回调,供外部使用。

    相关文章

      网友评论

      本文标题:iOS 给view加一个拖拽功能

      本文链接:https://www.haomeiwen.com/subject/hbqbmttx.html