VTMagic的使用介绍(二)

作者: 九流书生 | 来源:发表于2016-07-10 20:06 被阅读4440次

前言

距离VTMagic正式开源已经过去整整一个月,这短短的时间里收获了九百多颗star,在GitHub月榜Objective-C语言中,其排名基本一直维持在前三。目前第一是雅虎的AppDevKit,第三名是大家熟知的AFNetworking。坦白说,这样的成绩完全出乎我的预料,大家对VTMagic的认可让我满怀欣喜的同时也变得有些忐忑不安。针对VTMagic的改进,我慢慢开始变得谨慎,每一次改动都需要不断测试验证,以保证其可以正常运行。个人的力量是微小的,希望能与各位江湖高手一起完善VTMagic,参与开源项目将会是一件很有趣的事!

正文

上一篇文章中,已经初步介绍了VTMagic的部分特性和基本使用,同时也收到了不少反馈,本文将进一步介绍VTMagic使用中的一些要点和技巧,并针对部分反馈做一些总结,希望对各位开发者能有所帮助。

重用机制

该机制是整个框架的核心,它保证了单个模块中即使有数十上百个页面,应用内存依旧可控,不会出现突然暴涨,甚至被系统强制杀死的情况。在预加载机制下,VTMagic默认会加载当前页面和下一个页面,也就是说同时被加载的页面可能有两个,也可能有三个,具体视当前页面的位置而定。若当前页面处于两侧边缘,则被加载的页面有两个,若在中间则会有三个页面被加载。这也是有些开发者反馈的viewControllerAtPage:方法会被多次调用的原因。

而之前加载的其它页面则会在不需要时被移除,并放到内部缓存池中等待重用。当某个页面即将被重用时,方法vtm_prepareForReuse会被调用,该方法属于协议VTMagicReuseProtocol,需要开发者在各子页面中手动重写,通常可以在这个方法中清除页面旧数据、修正页面偏移等。

需要说明的是,可以通过将属性needPreloading置为NO来关闭预加载机制。在预加载机制关闭的情况下,VTMagic只会加载当前显示的页面,而不再预加载下一页,同时点击菜单项切换时,页面也不再有切换动画。

生命周期方法

当某个子页面出现或消失时,VTMagic能准确触发其相应的生命周期方法(viewWillAppear:等)。如果该页面是可重用的,则可以将网络请求放在viewDidAppear:方法中,然后根据menuInfo.menuId去请求当前菜单项的对应数据,作为必要的补充,请求时应该判断一下页面是否已经有了最新数据;与之相对的,我们应该在viewWillDisappear:viewDidDisappear:方法中将网络请求取消掉,以免被重用后页面数据错乱和造成不必要的流量开销。而如果页面是唯一的,即不会有其它页面重用该页面,这种情况下也可以将网络请求放在viewDidLoad方法中,特别是当预加载逻辑关闭时,即needPreloadingNO时。

谈到网络请求就不得不说加载本地数据的问题。针对可重用页面,当其menuInfo改变时(可重写menuInfosetter方法),我们通常需要为页面加载缓存数据,以保证滑动切换时能有良好的用户体验。关于缓存数据,可以是从数据库中读取,也可以直接将之前的页面数据保存到某个变量中以供后来使用,甚至可以从plist文件中获得,根据具体情况可灵活选择。

刷新和切换

  • reloadData方法会重新加载所有页面;
  • reloadDataToPage:方法会在重新加载所有页面时,同步聚焦到指定页面;
  • switchToPage:animated:方法用于在需要的时候切换到指定页面。

以上三个方法的使用场景各有不同,可根据具体情况灵活使用。需要注意的是,应尽可能避免在viewWillAppear:viewWillDisappear:方法中调用以上方法,否则会造成某些页面的生命周期方法不能准确触发,控制台会输出类似Unbalanced calls to begin/end appearance transitions for <VTGridViewController: 0x7fc3e2d43a70>的警告。这是因为这时的currentViewController与之后viewDidAppear:viewDidDisappear:方法中的currentViewController不是同一个,也就是说currentViewController的生命周期没有完整触发。而在viewDidLoadviewDidAppear:viewDidDisappear:或者其它地方调用以上方法都是没问题的。

多层嵌套

VTMagic支持多层嵌套,也就是在子页面中可以再嵌套一个VTMagic,类似需求一般常见于iPad项目,其使用原则与单个VTMagic的使用一致,并无其它明显区别。

跨层级业务处理

为方便跨层级处理业务,VTMagic提供了在子页面中直接访问上层最近主控制器的方法self.magicController,甚至你可以进一步通过self.magicController. magicView拿到当前的magicView。当然,你也可以通过self.vtm_pageIndex获取当前页面的索引。同样的,在主控制器中可以通过self.currentViewControllerself.currentPage获取当前显示的页面和索引。

自定义组件

VTMagic中几乎所有组件都支持自定义,框架本身主要提供核心的切换逻辑处理和良好的性能管理,开发者可根据业务需要自定义对外接口提供的任意组件。

自定义menuItem

你可以在menuItemAtIndex:方法中返回自定义的任意menuItem,只要它是UIBUtton类型即可。menuItem是顶部菜单栏中的单个菜单项,其可以支持文本、图片、文本+图片等几种格式。可见菜单栏文本的颜色和字体就是通过修改menuItem的文本和颜色来实现的,VTMagic本身并不直接提供修改文本和字体的接口。

自定义菜单栏两侧视图

可以通过属性leftNavigatoinItemrightNavigatoinItem在顶部菜单栏两侧添加任意视图,需要注意的是,被添加的视图应该有确定的size,然后VTMagic会自动完成相应布局。

自定义sliderView

由于需求各有不同,VTMagic提供的下划线、气泡等样式可能都不是你想要的,这种情况下你可以通过setSliderView:方法来自定义任意样式的sliderView,比如类似demo中的显示一个三角标识等。

自定义separatorView

如果需要,你甚至可以通过方法setSeparatorView:自定义顶部导航分割线,不过一般情况下应该是没这必要的。

其它

  • VTMagic中有许多有意思的小feature,比如scrollEnabledswitchEnabledswitchEvent以及navigationInset等等,详情请参见VTMagicView.h文件。
  • 关于VTMagic的所有重要修改都会记录在GitHub上的变更日志中,想知道每个版本都有哪些更新,可查阅该文件。

结束语

最后,按照惯例,如果你喜欢这个轮子,请留下一颗star,这是对作者最大的鼓励和支持,拜谢!!!假如你有更好的想法或方案,也欢迎提交pull request!!!GitHub地址

上一篇文章:VTMagic的使用介绍

相关文章

  • VTMagic的使用介绍(二)

    前言 距离VTMagic正式开源已经过去整整一个月,这短短的时间里收获了九百多颗star,在GitHub月榜Obj...

  • VTMagic的使用介绍

    VTMagic 有很多开发者曾尝试模仿写出类似网易、腾讯等应用的菜单分页组件,但遍观其设计,大多都比较粗糙,不利于...

  • UI控件和动画特效

    iOS开发UI篇--YXFilmSelectView(一个酷炫的电影选票View) VTMagic 的使用介绍

  • VTMagic适配iphoneX系列

    由于VTMagic作者老哥已经没有更新了。iphoneX系列适配并没有做。但是很好修改。 1、找到VTMagic库...

  • VTMagic框架数据重复问题

    Git地址: https://github.com/tianzhuo112/VTMagic Git上有VTMagi...

  • python

    一、介绍 使用二、

  • Vuex使用介绍(二)

    Mutation Vuex 通过commit一个mutation来对state进行更改。每个 mutation 都...

  • Git的介绍及使用(二)

    一、为什么要使用Git? 1、源代码管理的好处 方便多人协同开发 方便版本控制 2、Git的诞生 作者Linux之...

  • JIRA的使用介绍(二)- 配置和使用

    JIRA的应用配置(V7.8版本)很简单和直观,使用管理员账号登陆以后,打开相应的配置页面很快就能搞清楚。配置主要...

  • 美摄 SDK 的使用

    美摄SDK的使用(一)—— 产品介绍美摄SDK的使用(二)—— 框架介绍美摄SDK的使用(三)—— 短视频的录制工...

网友评论

  • a04ad4879b38:请教怎么返回同一个viewController,老是告警nbalanced calls to begin/end appearance transitions for
  • 方同学哈:后面的页面如果要添加空页面的话 好像显示不出来
  • 24号的信仰_1337:请问一下,怎么在子控制器中刷新副标题。比如说我的副标题是:全部(10),已完成(15),已取消(5),已删除(6);当我在子页面(已取消)这个页面刷新数据时候,已取消这个页面数据变成20了,我怎么刷新副标题的数字?
    方同学哈:后面的页面如果要添加空页面的话 好像显示不出来
    _Andy_:副标题 指的是什么?这个框架指提供了刷新menu标题的方法 [self.magicController. magicView reloadMenuTitles]
  • 孤单雨凉:push到下个页面的时候把我自己导航栏弄没了
  • 060ccf7f4dfb:你好,想问下这个库支持侧滑返回吗?有的话怎么设置啊,没有的话希望加一下
  • 起个名字好难O0:非常好用. 就是复用那个地方有疑问. 如果不使用复用, 会不会有其他影响. 还有就是菜单索引有没有写好的接口显示badgeValue.
  • 张廷:可以自定义headerView吗
  • fe70aa7fd29c:你好,我在项目中使用这个库,挺好用的。
    在xcode9 ios11下遇到了个问题:
    我在每个子页都有使用mj的上下拉刷新,上拉到底部的时候 会很诡异的整个子页向左滑动一点距离,且不触发刷新。这个问题在xcode9+ios11才会出现,之前使用的版本(非xcode9打包)在ios11下并没有这个问题。
    你有遇到这个问题么?
    fe70aa7fd29c:@大苏Andi 你说的问题和我的不太一样,我这个应该是横向tableView的滚动手势和VTMagic的子项(tableview正常方向)的手势问题。。
    _Andy_:我曾经遇到过 下拉刷新 有不自然滑动一点的现象,是因为 比如俩个子页面 第一个子页面下拉刷新动画还没结束,马上进入第二个子页面 开始下拉刷新,会出现下拉刷新动画冲突,而导致的子页面不自然的滑动一点。
    你可以在子页面的 viewWillDisappear方法里把刷新控件结束并隐藏,在viewDidAppear在显示我的就是这样解决的没问题。 mj最近也适配iOS11 建议你升级最新版本
  • _八阿哥:作者你好,当前控制器处于第三个,一共有5个控制器,我要怎样才能在第三个控制器,点击某个按钮,让它自动滑到第一个子控制器呢
    _八阿哥:@大苏Andi :sob: :sob: 多谢大神,大神
    _Andy_:有两种方式可以实现
    1.[self.magicController.magicView reloadDataToPage:0];
    2. [self.magicController.magicView switchToPage:0 animated:YES];
    建议用第二种
  • 伊织随意写:你好,我们导航栏上的切换 ,是一个UISegmentControl,不是button,请问如何集成你的框架?
  • 羊肉泡馍啊:已集成进项目中
  • 颓阿废:请问VTMagic滑动切换controller和tableview中cell左滑删除有冲突应该如何处理?
  • 马克雅:请问一下,如何滑动返回到上一个controller
  • 马克雅:顶一个:blush:
  • Shenry:请您将VTMagicMacros.h 中 #define RGBACOLOR(r,g,b,a) 和 #define RGBCOLOR(r,g,b) 的名字前加上VT吧,已经有太多第三方库自定义的名字叫这个,导致重定义了
  • c9b0aa8daecb:右侧view设置半透明无效
  • 神一样的男人卫:写的很好,可见功底深厚!谢谢大神的分享!
  • c066fe49abc4:你好,我想请问一下,集成VTMagic后,点击状态栏返回到顶部的功能失效了,该怎么去还原这个功能呢,我把VTMagic中用的scrollview的scrollToTop都设成了NO,但是还是不能返回到顶部
    _Andy_:- (void)viewDidAppear:(BOOL)animated {
    self.tableView.scrollsToTop = YES;
    }
    - (void)viewWillDisappear:(BOOL)animated {
    self.tableView.scrollsToTop = NO;
    }
    本小明:大兄弟你是用哪个版本的系统测试的?我真机测试iOS9.2,不能返回顶部。但是模拟器10.3可以。现在不知道是模拟器和真机的差别还是版本的差别
  • 羊肉泡馍啊:已集成进自己项目
  • 0a9219cb2912:感谢开源,代码十分整洁,用着也很舒服,但是看里边大量的布局计算都是在主线程中进行,用profile测了一下,正常使用时不会有问题,但是在快速点击menuBar切换时,fps还是有些不稳定,我觉的以后这也可以当做是vtmagic的一个优化方向
  • 白水岂能度日:你好,大神!本人做的几个项目都用到了你的框架,真的非常的棒,非常的喜欢,我会一直支持你的
  • _八阿哥:需要说明的是,可以通过将属性needPreloading置为NO来关闭预加载机制。在预加载机制关闭的情况下,VTMagic只会加载当前显示的页面,而不再预加载下一页,同时点击菜单项切换时,页面也不再有切换动画。


    大神.能不能修改一下源码,即使将属性needPreloading置为NO,点击菜单项也能有动画切换效果
  • _Andy_:有群吗 大神?
  • Eason_Gao:同重复使用一个页面的时候,需要实现缓存,避免重复请求,在使用过程中,初始化viewControllerAtPage会执行两次,menuInfo的数据在set方法中会多次复制,如demo中所写,实际每次来回滚动切换,数据源会出现错误,在读取loadlocalData的时候,数据并不是当前页面的数据
    _八阿哥:@Eason_Gao 群主demo里的哪个模块呀。在线等
    Eason_Gao:@_八阿哥 参考群主demo里面处理的逻辑
    _八阿哥:@Eason_Gao 那你是怎么解决的啊.老哥,我也有数据请求和缓存问题
  • Hither:解决了 - (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.navigationController.view sendSubviewToBack:self.navigationController.navigationBar];

    }

    -(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.navigationController.view bringSubviewToFront:self.navigationController.navigationBar];

    }

    这样写 就可以了
  • Hither:你好 我在viewWillAppear隐藏导航栏 因为需求在viewWillDisappear的时候我需要让导航栏显示 这样后面的页面才可以使用 但是 就会出现一个bug: 每次回到这个页面 导航栏 都会出现一下 再消失
  • 白羊的羊:您好,我现在想不实现复用, 在didLoad中请求的数据,但是还是会页面数据错乱, 该怎么办呢?
  • 48e030ceaec7:大神,是我错了,我不该吧刷新写在didLoad,我感觉我还是要学习一个
    九流书生:@吴慕 嗯,关于复用的问题可以看看demo中的处理。
  • 48e030ceaec7:大神,复用的时候有点问题,页面复用有时候导致数据错乱,某一页的数据可能是其他页面的,需要理解刷新
  • 48e030ceaec7:哥哥,没有你们这种大神,我感觉我都写不出项目了,我自己写了个类似的轮子,惨不忍睹
    九流书生:@吴慕 谬赞了,都是一步步走过来的,慢慢地就会好很多。
  • Towardfai:使用了你这个库后 我还需要原有的导航栏 这么破。你的headerView虽然可以显示出来 但不能编辑
    九流书生:@Towardfai 你好,demo中默认把系统导航隐藏了(homeNav.navigationBarHidden = YES;),你将其显示出来就好;另外,你可能需要把self.edgesForExtendedLayout = UIRectEdgeAll;注释掉,避免VTMagic的导航被系统导航遮住,当然你也可以直接修改VTMagic的约束。UIRectEdgeAll的作用是为了让底部tabbar有半透明的穿透效果。
  • 颜sir:弱弱的问一句reloadDataToPage:在哪里类里面,都不知道怎么调用
    九流书生:@颜sir 在VTMagicView.h中,你搜一下就能找到它。
  • 颜sir:自定义菜单栏两侧视图,左边和右边有什么区别吗?为什么我设置左边,然后设置居中,居中不了,设置右边可以居中
    颜sir:@九流书生 懂了,之前没有很好的理解到navigationInset
    九流书生:@颜sir 你好,这个问题可以参见demo中Center模块的处理,需要修正navigationInset。
  • juvelins:你好 我想问下 我在子界面 push到 下一个界面 当我返回的时候 怎么才能让它滚到当时的子界面 现在都是滚动到第一个界面
    九流书生:@juvelins 呃,其实我有点懵,没太懂你描述的问题,不过VTMagic本身并不会拦截事件。
    juvelins:谢谢 回复 我还遇到一个问题 就是 我子界面写的tableview 如果我在子界面上写一个封装的view view 上面的控件 不现实 或者不能点击? 如果 我在主界面 就没有问题
    九流书生:@juvelins 你好,之所以出现这种情况,大概是因为你在主控制器加了这句代码[self.magicView switchToPage:0 animated:YES];其作用是切换到任意指定页面。
  • 若锦:你好,我想问一下,菜单栏可以自定义放在任何位置么 :stuck_out_tongue_winking_eye:
    回味岁月:@若锦 最近同样在做这个效果 想问下你做出来了没 有没有demo共享一下 多谢了
    若锦:@九流书生 比如说在菜单栏的上面还有一个头视图,那这时候菜单栏的位置应该是从头视图之后开始了。其实我想要的一种效果是,有一个头视图,头视图下面有个菜单栏,左右滑动可以切换菜单栏对应的内容;而上下滑动时,如果上滑的距离超过了头视图的高度时,固定住菜单栏的位置,这时候再继续上滑的话只是菜单栏对应的内容上滑,而菜单栏是悬浮的,但是仍旧可以左右滑动切换菜单栏。 :joy:
    九流书生:@若锦 你好,这是一个有意思的问题,不知道你是希望实现什么样的效果?
  • 443718761557:楼主大大,我几个页面 就数据类型不同 如何做到数据互不影响 又能添加下拉刷新上拉加载功能
    九流书生:@不愿透露姓名的白先生 你好,关于页面复用以及数据处理的问题,请参见demo中的Home模块。。
  • Cloud_Wind:我有7个界面,在界面重用时 ,怎么让每个界面都加载不同的URL呢 :pray:
    九流书生:@Cloud_Wind 如果只是数据不同,那显然是适用于复用的,Home模块中的savePageInfo和loadLocalData方法不知道你有没有看,这是其中一种解决页面复用后的数据处理逻辑。
    Cloud_Wind:我看Home模块的Demo了.不一样,我的7个界面其实还是一个ViewController,只是初始化的时候传入一个参数,让显示的内容不同.但是一复用的话,就是显示前三个界面的数据,之后的就开始复用了,重复了前三个界面的数据了.是不是这种情况就不能采用复用了,每次都是重新alloc init 一个新的控制器呢 :unamused:
    九流书生:@Cloud_Wind 你好,每个页面传递不同的menuInfo,然后根据menuInfo来加载不同的页面数据,可以参考demo中home模块的处理。
  • e44296410c03:我喜欢
    九流书生:@东商通 多谢支持~! :beers:
  • Scott_Mr:我想问下,如何实现已经加载过的页面不在进行网络请求呢?
    Scott_Mr:@九流书生 使用的时候遇到一个问题,一开始的时候,会请求第二个界面的数据,当滚动到第二个界面的时候,会请求第三个界面的数据,依次类推。请问怎么解决呢?
    九流书生:@Scott_Mr 关于这点可以参见demo中VTGrideViewController的处理,最新一次提交data cache。
    九流书生:@Scott_Mr 这涉及到数据缓存的问题,一种方案是menuId从数据库中读取相应的数据;另一种方案就是用一个字典把每个页面的数据保存下来,字典的key就是menuId,这个字典可以保存在主控制器中,也可以用个单例来管理,后者可以减少与主控制器的交互。
  • davisjy:已集成进自己项目
    九流书生:@davisjy 多谢支持,如有问题可以随时@我!:beer:
  • 9555df347414:大神的奉献精神,真是无言以表。半夜把你的框架套在项目上了,还须再改造和调试。非常流畅,这是我见过的国内最好的框架之一。后续自定义的细节以及缓存的配置还望兄弟多多指导〜〜〜
    九流书生:@eason_chan 非常感谢你的支持,如有疑问欢迎随时@我。

本文标题:VTMagic的使用介绍(二)

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