美文网首页收藏iosiOS开发攻城狮的集散地iOS
iOS侧滑菜单-完全解耦-一行调用

iOS侧滑菜单-完全解耦-一行调用

作者: 从来吃不胖 | 来源:发表于2017-03-05 22:41 被阅读1900次

    DYLeftSlipManager

    一行代码实现侧滑。完全解耦,两个界面之间不需要有任何耦合。基于控制器自定义转场。

    Github:https://github.com/maybeisyi/DYLeftSlipManager
    先上图:

    DYLeftSlipManager.gif
    使用:

    导入#import "DYLeftSlipManager.h"

    // 注意这个控制器是右滑视图控制器,由于完全解耦,所以在DYLeftSlipManager内部是对该控制器强引用防止销毁。
    
    LeftTableViewController *leftVC = [LeftTableViewController new];
    
    [[DYLeftSlipManager sharedManager] setLeftViewController:leftVC coverViewController:self];
    
    // 这个self是覆盖在右滑视图上层的控制器,一般应用中就是UITabbarController
    
    

    嗯哼。是完全解耦的,你可以在任意地方调用这两句代码即可。
    具体实现请看代码(基于控制器转场,并非 视图+手势 )。

    相对于网上其他DEMO来说,本例是利用了控制器转场实现的,其他DEMO基本都是View上加侧滑View,这样的话两个界面之间耦合度太高,两个View都归一个C管,不能忍~~~本例就是两个控制器,各管各的业务。

    本例的简析将在后续更新到简书,目前简析可在本人博客查看:daiyi.pro

    ——————————————我是分割线————————————————

    标题是简析,不是解析

    所以我只谈思路,不谈详细实现

    DYLeftSlipManager是一个侧滑菜单组件,它与别的侧滑菜单不同的是,它将“侧面菜单”以及“主页面”之间完全解耦合。

    GitHub地址:https://github.com/maybeisyi/DYLeftSlipManager

    之前在各大论坛上看到的侧滑菜单,各种仿QQ侧滑菜单,仿XX侧滑等等,均是在同一个ViewController(以下用VC代替)中,添加一个侧面的视图,然后通过手势balabala的。能用吗?当然能用,只要你不嫌你的VC够臃肿。

    侧滑菜单页面的内容往往和主页面的内容关联度不大(部分应用中也有见到是有关联的),一般来说都是可以独立为一块业务的(有关联的基本也能抽象为一块独立业务)。在这种场景下,你认为两个业务同写在一个VC里真的好吗?

    所以就有了这个轮子。

    轮子思路

    1. 如何抽象出这部分的业务?

    业务的抽象还是需要靠类(甚至于模块)来进行划分。

    2. 如何分离出这部分页面?

    页面的分离,要么是自定义view,要么是另开一个VC。

    自定义view可以实现页面的分离,但是业务逻辑很难全都塞入view中进行管理,因为业务一般是VC或者单独的业务类来进行管理。所以另开一个VC是目前较佳的选择。

    3. 如何在当前侧滑的场景下另开一个VC?

    首先不要将ViewController和view在脑海中混在一起,不要将VC当做view。VC是一个抽象的内容,只是一堆代码,你是看不见VC的,App上你看见的才是真真切切的view,只不过VC通常作为一个“完整页面(一个手机屏幕大小)”的“容器”存在而已。所谓“容器”,你理解成view是VC的一个属性即可。

    为了帮助你理解VC和view的关系,这里我举个简单的小例子:

    这里我自定义一个继承自NSObject的类:MyDog(用这个名字是为了有别于VC,这就是一条啊,没错!

    @interface MyDog : NSObject
    
    @property (nonatomic, strong) UIView *view;
    
    @end
    
    @implementation MyDog
    
    - (instancetype)init {
        if ((self = [super init])) {
            [self loadView];
        }
        return self;
    }
    
    - (void)loadView {
        self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        [self viewDidLoad];
    }
    
    - (void)viewDidLoad {
        // balabala
        [self viewWillAppear];
    }
    
    - (void)viewWillAppear {
        // balabala
        [self viewDidAppear];
    }
    
    - (void)viewDidAppear {
        // balabala
    }
    
    @end
    

    这里的狗,含有一个view的属性,还自定义了一些和VC“很像”的方法。

    到这里应该没问题。

    然后我们在默认的ViewController.m中,addSubview,把狗的view显示出来:

    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        MyDog *dog = [[MyDog alloc] init];
        dog.view.frame = CGRectMake(100, 100, 100, 100);
        [self.view addSubview:dog.view];
    }
    
    @end
    

    没问题吧,狗的view确实显示出来了吧?那么,狗有个view,新建一个VC也有个view,我们是不是可以把dog换成VC呢?

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        UIViewController *VC = [[UIViewController alloc] init];
        VC.view.frame = CGRectMake(100, 100, 100, 100);
        VC.view.backgroundColor = [UIColor redColor];
        [self.view addSubview:VC.view];
    }
    

    OK吧?现在你想清楚VC和view的关系了吧?

    你没想清楚MyDog和VC的关系?这么说把,Dog无法知道view在系统中何时willAppear、DidAppear等节点,所以无法精确的管理view的生命周期,但是VC可以,因为VC是苹果提供的类,它的名字是“UIViewController”,也就是“view的控制器、管理器”,所以VC能管理view的生命周期,所以我们在VC里写业务会更方便开发!

    说了那么多,我就想说明一个观点:

    在一个VC里(主页面),要另开一个VC(侧滑菜单页面),那就创建一个嘛,然后把侧滑页面的view addSubview到主页面里不就完事了?

    好了,业务与页面都被抽象到另一个VC了(当然了你要自定义一个侧滑菜单VC)。那么主页面的VC和侧滑菜单页面的VC已经逻辑分离,耦合松散了。只不过,主页面此时还必须知道有“侧滑页面”这个VC的存在。

    4. 进一步解耦合

    在第3点中,我们已经初步解耦合了,但是是不是有更优雅的方式?

    回想NavigationController,这个控制器存在的意义是什么?它可以将两个VC进一步解耦合。

    这个进一步解耦合是如何体现的呢?回想第3点,我们已经做到了将两块业务分散到了两个VC中,但是,view还是完全耦合在一起的,因为主页面的view和侧滑菜单页面的view是通过addSubview的方式进行关联的。而NaviagtionController就是进一步将view解耦,通过NavigationController.view。

    每个导航栏都有自己的view,上面只有一个NavigationBar视图,下方是空视图,第一个VC的view是addSubview到导航栏的view上面的。然后我们push了第二个VC,那么第二个VC的view此时就不是直接addSubview到第一个VC的view上去的,而是add到NavigationController.view上去的,然后伴随推入的动画将第二个VC的view进行显示。此时第一个VC的view和第二个VC的view,不在是“父子”关系,而是“兄弟”关系了。

    能理解这层解耦合关系吧?那么我们来说说我们的侧滑菜单如何解耦合。

    5. 侧滑菜单如何解耦合—控制器转场

    这里不细说控制器转场如何实现,想学习的google一堆。这里想说的是转场究竟是个什么东西。

    控制器转场就是通过一系列动画,操作两个VC的view进行切换显示。切换显示的时候,会有两个VC的父view:containerView,然后两个VC的view在上面add、remove,再加点动画,就可以了。

    无论是push还是present,都是转场,就是操作view的addSubview或者removeFromSuperview

    一是给两个VC解耦,二是做动画,用户体验更友好。

    控制器转场的本质就是view做动画,操作view,和你的VC没有太大关系

    明白这个道理后,熟练使用各种动画技能的你就可以在转场中行云流水了。

    等等,侧滑可是两个界面同时显示啊!你说你都能控制两个view了,你难道不能控制view的frame,不能控制view的大小,不能控制两个view怎么叠加怎么摆放?不要被VC传统的用法束缚,在这里,view才是你的主角。

    轻总结

    新手往往被苹果指定的用法所束缚(如VC和view的关系),那是因为没有清楚理解苹果提供的“用法”的本质。当然,苹果的用法已经足够优秀,你不必考虑部分细节也能进行使用,但是,理解“用法”的本质,才能让你走的更远。

    相关文章

      网友评论

      • 一纸符文:侧滑Vc是TableView点击cell不跳转
      • _Waiting_:你好,如何调整两个VC的前后顺序,比如我想上leftVC在上,coverVC在下。
        从来吃不胖:@_Waiting_ add leftVC的顺序可以改变,也可以通过加阴影改变视觉上的层次关系,当然如果你需要在右滑的时候,动画效果是让leftVC从左边出来,那么整个动画的方法需要稍微做下调整。具体看你需求了
      • 黄河石:讲的真的不错 给个地址我给你打赏
        从来吃不胖:@黄河石 大哥你有你这句话我就满足了,打赏什么的都不重要:smile:
      • neobuger:右滑 展现 左边控制器,然后 来回滑动多次,再快速滑向左侧关闭, 左边会有 黑色的背景闪现
        从来吃不胖:@neobuger 好的,我去排查下
        neobuger:有一定概率.我操作还蛮容易复现的
      • 2aac077ac5a0:侧滑的tableView怎么“push”跳转呢?
        名a字太难搞了:用代理完美解决啊!
        从来吃不胖:@知企网郭川陵 这个是侧滑tableview与主页面之间的业务联系。你可以用通知,毕竟是两个解藕页面之间的通信。
        从来吃不胖:这个方案的本身就不是希望在侧滑页面里push二级页面等等各种复杂操作的。你可以在:点击侧滑页面VC里的内容时,让主页面VC去push那个VC2,同时dismiss侧滑页面VC
      • 58fe5465d15f:刚好需要用到,谢谢分享!
        有个小问题,和ScrollView有点手势冲突,ScrollView里面我放了2个TableView
        58fe5465d15f:@从来吃不胖 我现在碰到个这样的问题,左边侧滑出来的VC放到一个Nav里面,点击VC里面的内容Push到一个新的VC2里,此时VC2并没有全屏显示,右边仍然显示着原来被覆盖的页面。
        从来吃不胖:@Raysonly ScrollView的冲突确实还没有处理,既然有需求,我后续空的时候加上这个处理:smiley:
        58fe5465d15f:我现在暂时的解决办法是,把ScrollView离开左边屏幕一点
      • Q007001:- (void)DYL_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {\
        [self DYL_pushViewController:viewController animated:animated];


        这个为什么不会形成死循环???
        Q007001:@从来吃不胖 gold。你在哪工作呢
        从来吃不胖:Method swizzling。方法的实现已经交换了。此时调用 DYL_pushViewController:animated:的时候实际执行的是原UINavigationController的pushViewController:animated:方法
      • 文雅的人字拖:你好,请问下,你的demo内的KVO Methods中的NSKeyValueChangeKey一直报错是怎么回事呢?
        文雅的人字拖:@从来吃不胖 我用的是xCode7.2,会不会是这个问题呢?
        从来吃不胖:@唱情歌 可以简单看下报错的提示吗?用的是什么版本的iOS系统?
        从来吃不胖:@唱情歌 稍等我看一下
      • WangRB:赞一个,好用
        从来吃不胖:@WangRB 我这边测试是不会和导航控制器的右滑返回冲突的,额,希望你那边提供更多的条件,我可以排查下
        从来吃不胖:@WangRB 主控制器push出的VC吗?请问是什么手机型号?什么iOS版本?是否有自己手动禁止navigationController右滑返回?
        WangRB:有一个问题,push出的vc左滑也会显示侧滑菜单
      • 给你快乐:很好用,谢谢作者
        从来吃不胖::relaxed: 不好用的尽管说粗来

      本文标题:iOS侧滑菜单-完全解耦-一行调用

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