可拖拽的小窗口,最好用?

一、前言

  • 1、写了10多天的小程序代码,有兴趣的可以看我这篇小程序官方文档-小程序版【持续更新】,被坑得有点晕,突然想换换口味,写点iOS的,看群上有人提过这个拖拽view的功能,应该挺多人需要的,那就造一个分享吧。

  • 2、公司有自己的一个直播项目,看其他直播app都有小屏幕可拖拽播放的view(如下图),虽然还没有这个需求,早点准备好。

截图来自某牙直播
  • 3、而且很久没分享了,像往常一样,封装轮子的过程都会详细介绍,分享更多的都是封装的思想。

  • 4、来看看效果图先吧:

    演示效果图,还可以吧

二、功能分析(针对所有控件)

  • 1、可拖拽。最基本的功能,拖出父容器松手后可复位,可关闭。

  • 2、拖拽不遮盖。同级层次的控件,如果拖拽过程中出现重叠,会显示在最上层。

  • 3、可吸附边界。吸附这点参考苹果的AssistiveTouch,只能在屏幕的左边或者右边,可关闭。

  • 4、弹簧效果。如果超出屏幕,会有弹簧效果,这点参考scrollView 的 bounces 效果,可关闭。

  • 5、支持xib、storyboard 参数设置。很多控件都是在xib或storyboard 中创建,此时可通过,看下图:

支持xib、storyboard 参数设置

三、API 分析设计

  • 1、是否允许拖拽,默认关闭,支持xib、storyboard 参数设置
/**
 *  @author gitKong
 *
 *  是否允许拖拽,默认关闭(可以在XIB或SB中设置)
 */
@property (nonatomic,assign)IBInspectable BOOL fl_canDrag;
  • 2、是否需要边界弹簧效果,默认开启,支持xib、storyboard 参数设置
/**
 *  @author gitKong
 *
 *  是否需要边界弹簧效果,默认开启(可以在XIB或SB中设置)
 */
@property (nonatomic,assign)IBInspectable BOOL fl_bounces;
  • 3、是否需要吸附边界效果,默认开启(可以在XIB或SB中设置
/**
 *  @author gitKong
 *
 *  是否需要吸附边界效果,默认开启(可以在XIB或SB中设置)
 */
@property (nonatomic,assign)IBInspectable BOOL fl_isAdsorb;

四、功能实现分析

  • 1、分类或继承实现。因为需要支持所有控件,我们都知道控件都是直接或者间接继承 UIView ,此时可以有两种办法实现,继承分类 ,此时我是用分类实现的,至于为什么呢?

    • (1)、如果我当前的view是已经继承了另一个自定义view,而且功能很独立,此时如果要给当前view添加拖拽功能的话,就必须融合两个功能的代码,这将变得很麻烦,而且会很乱。

    • (2)、如果我需要给一个按钮添加拖拽功能,那么继承就没办法实现了,因为你给这个按钮修改了继承,就没了自带的功能了。

  • 2、监听拖拽。拖拽事件可以通过 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 方法去监听,也可以通过添加 pan 拖拽手势,至于为什么要用 手势呢?

    • (1)、需要在分类中实现 touchesMoved 方法,此时如果外界也实现了这个方法,那么就很容易起冲突。
    • (2)、虽然动态修改拖拽功能开关,但 会 多次调用 touchesMoved 方法,即使关闭了拖拽功能,相对手势实现就没那么灵活了。
  • 3、Setter 方法里添加pan事件。一开始想到的是通过 runtime 的 Swizzle 替换掉 系统的 init 方法,进而在自己的方法里面实现 拖拽手势添加,但后来考虑到,此时是给UIView 添加分类,而页面上的所有控件都是UIView 的 子类,此时 init 就会调用多次,会造成页面显示慢;于是直接在setter方法里面判断,当需要拖拽的时候,我才添加事件,不需要拖拽的时候移除手势,算是一个小优化。此时还需要记录当前控件在父容器中的 index ,这个等下就知道要用来干嘛。

  • 4、遮盖处理。我们都知道,控件通过 addSubviews 添加到父容器中,是有顺序的,后面添加的会在上层;此时如果我先添加 view1 在添加 view2,我拖拽 view1 到 view2 的时候,就会被 view2 挡住。做法如下:

    • (1)、遍历父类view 的 subViews 数组,判断是否与当前view重合,用系统自带的 CGRectIntersectsRect 方法判断。
    • (2)、在拖拽开始(UIGestureRecognizerStateBegan)的时候,用 bringSubviewToFront 将拖拽的view 移到最上层。
    • (3)、在拖拽结束(UIGestureRecognizerStateEnd)的时候,判断此时状态是否还重合,如果不重合,通过 insertSubview 将控件重置回原来的顺序(通过上面第三点记录的 index
  • 5、支持xib、storyboard 参数设置。这个只需要添加一个 关键字修饰就行 IBInspectable ,用法可以看我API 设计,这个主要作用是使view内的变量可视化,并且可以修改后马上看到

  • 6、弹簧效果和吸附效果。这个可以使用UIView 的 动画就可以实现,此时有一个注意点,判断吸附到左边还是右边,比较的应该是绝对位置,而不是相对位置,需要加上父类的x值

if (gesR.view.fl_centerX + self.superview.fl_x > self.superview.fl_centerX) {
    [UIView animateWithDuration:0.25 animations:^{
        gesR.view.center = CGPointMake(self.superview.fl_width - self.fl_width / 2, y);
    }];
    
}
else{
    [UIView animateWithDuration:0.25 animations:^{
        gesR.view.center = CGPointMake(self.fl_width / 2, y);
    }];
}
计算小坑

五、注意点:

  • 1、如果你是使用约束来布局的话,此时可能出现当你拖拽出一定范围后,能正常停留在当前位置;但当你此时拖拽后的位置在约束好的位置附近,就会被吸附回去,如下图:(此时图片是使用约束布局
使用约束布局可能会出现这种情况
  • 2、如果手势失败,会有断言提示。

六、总结

  • 1、为了方便大家使用,支持cocoapod,通过 pod search FLDragView 就能搜到。如果你搜不到,先清理一下吧,执行 rm ~/Library/Caches/CocoaPods/search_index.json 执行完重新 search 就行

    cocoapod
  • 2、代码不难实现,具体代码就不拷贝上来了,代码中计算相对多一点,文字分析应该比较清楚了,如果还有什么其他问题,尽管找我。

  • 3、Github地址 ,欢迎大家关注我,喜欢给个star 和 like ,你的支持是我最大的动力,会随时更新原创文章喔!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,582评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,629评论 4 59
  • 在Android逆向分析(2) APK的打包与安装一文中对资源编译过程的介绍中,笔者提到了overlay(重叠包)...
    MarkZhai阅读 10,416评论 1 15
  • 人类总是爱和自己闹对立,用自己目前的痛苦哄骗自己的希望,又用并不属于自己的前程,来欺骗目前的痛苦。人类的一切行为,...
    章可可阅读 438评论 3 1
  • 二水: 展信佳。 今天学校里迎新生,第一项升国旗,想起原来我们四个人的学校升国旗的时候。噗,我每次都是站在护旗手迎...
    铭1993阅读 337评论 0 0