MBXPageViewController是什么?
这里是原作者的主页,Moblox也是参照的其他作者的源代码改的,为了集成更多的样式。
这个控件是我一个同事集成到项目中来的,集成后UI那边添加了两个需求:
- 点击title上面的按钮需要让当前页面滚动到顶部
- title下面的tabIndicator需要跟页面同步滑动。
于是我不得不去研究了下MBXPageViewController的源码。
MBXPageViewController是仿照RKSwipeBetweenViewControllers写的,通过源码可以看出并不是一个完成品,因为RKSwipeBetweenViewControllers是支持tabIndicator与页面同步滑动的。
所以第二个问题就简单了,把MBXPageViewController完成就可以了。
首先我对比了MBXPageViewController和RKSwipeBetweenViewControllers的优缺点。虽然MBXPageViewController的watch和fork远低于RKSwipeBetweenViewControllers,
MBXPageViewController的使用还是远远比RKSwipeBetweenViewControllers简单清晰,而且能适应更多的特殊UI情况。
使用MBXPageViewController.
很简单易懂,有可能有人不理解,为什么没有看到addChildViewController或者addSubview之类的方法?其实这些都封装在了[MBXPageController reloadPages]方法里面
进去看源码就会发现:
- addChildViewController我的理解就是重新设置子controller的父controller,也就是层级关系,防止后面再Push或者Present新窗口的时候出错
- addSubview就更加直观了不需要多解释,没有这句话咱们就没有View可以显示了。
需要注意的是[[self MBXDataSource] MBXPageContainer]这个方法,他是MBXDataSource协议里必选的方法
说到这里就必须说说为什么我认为MBXPageViewController的使用远远比RKSwipeBetweenViewControllers简单清晰,就是因为两个协议:
- MBXPageButtons 就是标题栏上面的按钮,需要注意的是MBXPageViewController并不管按钮的显示,MBXPageViewController只负责帮我们绑定按钮的触摸事件,
显示正确的对应的页面
- MBXPageControllers 这个就是咱们页面的数组了。
- MBXPageContainer 是页面的容器,只需要返回MBXPageViewController所在的UIViewController的container就行。
- MBXPageChangedToIndex 是一个提供给用户更新按钮状态的方法,当页面索引改变后就会触发这个方法,用户应该在这里跟新title
上面按钮和tabIndicator的状态.
整个协议的完整实现大概应该是这个样子:
怎么样,是不是非常简单清晰。下面需要解决的就是我们UI提出的需求问题了,也很简单,修改绑定button的事件:
只加了一句[weakSelf updateCurrentPageIndex:tempIndex];然后我们可以自己在updateCurrentPageIndex方法里判断,如果当前索引跟传入的索引相同则当成点击事件来处理,否则则是页面切换事件,需要跟新button的状态,
这样我们就解决了第一个问题。第二个问题比较复杂,我到现在都还没完成搞清楚why,只知道要这么做。
我们先把MBXPageControllerDataDelegate协议拓展一下,添加两个方法:
- MBXPageTabIndicatorStartOffset返回tabIndex被选中时的tabIndicator的X坐标。别问我为什么要这么做,我也是一知半解。
- MBXPageSelectdViewOffset就是事实跟新tabIndicator的X坐标的方法,offset就是X的新坐标。这两个接口有了之后就需要判断在那里加了。
通过分析源码可以看到有个很诡异的事情:
_pageScrollView.delegate = self;可以整个代码里并没有实现ScrollDelegate的方法,我对比了一下RKSwipeBetweenViewControllers才发现原作者并没有copy这个delegate,原因可能是他的项目里当时不需要这个特性。
很显然我们需要实现这个ScrollDelegate,并在滑动过程中同步调用MBXPageSelectdViewOffset来跟新tabIndicator的X坐标:
必须得承认,如果没有看RKSwipeBetweenViewControllers我到死都不可能完成这个方法。了解pageController这个容器的都知道,这个容器为了节省内容,会在他认为合适的时候把看不到的子controller移除。
这可真是个要命的特性,我刚开始的想法理所当然的认为scrollView.contentOffset.x/scrollView.contentSize.width就是滚动的比例,然后根据这个比例来更新咱们的tabIndicator。可是当我
把scrollView.contentOffset.x和scrollView.contentSize.width打印出来后我傻眼了,简直混乱的不要不要的,完全不对头。之后在一段时间的探索后我猛然发现,原来RKSwipeBetweenViewControllers有
同步跟新tabIndicator这个特性。。。
下面是最后的效果图: