什么样的开源界面控件才最好用

前段时间做了一个万年历App,在github中搜索了一下日历,果然不出所料,一大批开源的日历控件。纠结了一下,要是自己从头写要考虑的东西很多,而且用的思路基本上也是这些开源控件的思路(后面会总结一下大致有几种思路来实现一个日历)。于是最终决定用现有的轮子,没成想就掉到深坑里去了。后来上线了第一个版本后,赶紧自己写了一个。同时不免思考了一下,怎么样设计一个开源的界面控件,别人用起来才舒服呢。

对设计一个开源控件的思考

对于开源的界面控件,我认为可以大致分两种,一种像是Toaster这样的,只是App的一个附着品、点缀,不需要对UI进行很大的深度定制。一种像是日历这样的,对于日历App,日历控件必然是它的重要部分,一般都需要对它进行很大的改造才能达到想要的样子。下面分别针对这两种控件,谈一谈自己的一点反思。

对于前者,因为别人在集成时不需要进行太大的改动,所以最好做到能够不去改动控件的源代码,就能定制想要的效果。这其实比较考验想象能力,你能想到哪些可以让别人去定制的呢?控件的背景颜色、字的颜色、字体、icon、位置、动画的有无等等。根据过往经验,总结了一下在封装时的几个要点:

  • 隐藏实现的细节,对于Objective-C就是将公开的接口放到.h文件中,其余的实现过程中的辅助方法放到.m文件中。对于Swift就是利用fileprivateprivatepublic等域关键字来做限制。
  • 公开接口的设计,我目前想到有3种方式:
    1. 将可定制的控件暴露出去,比如有一个label,公开后,就可以通过xxView.label.textColor = UIColor.yellow这样来设置。但可以控制该label不能被调用者创建,对于Objective-C,可以设置为readonly的。对于Swift,可以将set方法设置为private的:public private(set) var label: UILabel?
      1. 暴露方法出去供使用者调用,将控件保持在内部,这样使用者能进行哪些定制一目了然,也完全受限于控件的开发人员了。
      2. 走配置文件,将所有定制时需要的资源都定义到一个类似Appearance.h这样的文件中,或者plist等文件中。调用者在使用时来改相应的资源配置即可,无需再去关心代码细节,但其实也是对源代码进行了改动,如果是把控件封装成了一个Framework,这种方式就不太适合。
  • 尽量不要耦合其他的库,这无疑会方便别人使用,只要拖进你的这一个库就行了。如果耦合其他的库,还有可能正好碰上使用者的工程中也有这个库。有些时候真的可以避免去用第三方的库,只要自己愿意动手~
  • 最后最好支持CocoaPodsCathage集成。最终达到在需要时查一下公开的API接口就能找到。

再来看后者,后者通常是要改源代码才能达到预期效果。那上面的一些思想我认为就不太试用了,对这次的经历,也反思总结了以下几点:

  • 因为这类控件作为App的重要部分,使用者对它的定制也必然五花八门,纵然你接口暴露的再灵活,也很难满足所有的要求。所以很大的可能别人要对源码进行修改。提供CocoaPodsCathage集成就没多大意思了。
  • 既然人家是要来改源码的,那就把控件的实现思路、布局思路在代码上体现的清晰一些,别人不需要花太多的时间来琢磨就能知道控件的整个样子。如果自己都觉得看着代码缕清楚比较费尽,那在开源出去的时候也顺带提供设计文档。
  • 走配置文件来定制控件的样式在这里就比较适用了,否则在控件的实现稍微复杂些时,可能要通过delegate来让外界设置样式。太频繁的判断delegate的方法是否存在,然后调用,其实也会对性能有一定的影响。(我这次找的这个日历控件就是这么干的 = =)
  • 在实现时的重点思考不是别人可能会定制哪些地方,我要怎样暴露接口他才改起来方便。而是别人要添加一个视图时,或改一个视图位置时,怎样才能快速的找到要改动的位置。

我按照以上的这种想法,重写的日历控件:https://github.com/shinancao/TestCalendarView,不仅思路简单,而且快速滑动也很流畅,客观您感兴趣可以看一下~

日历可以有哪些方式来实现?

从github上开源的日历控件看,主要的实现方式有以下几种:

  • UICollectionView来做,这是最简单的方式了,不用考虑每一行月份View要复用的情况。每个月份是一个section,每一天是一个cell,重写UICollectionViewFlowLayout,计算一下每个cell的位置大小。
  • 重写UIView的drawRect方法,将日历画出。每个月份画出来,翻页的处理添加手势,然后给layer添加动画。这种方式在性能方面比较糟糕,drawRect被称作内存魔鬼,不恰当的使用会使内存暴增。
  • UIScrollView来做,这种方式就非常灵活,想怎么来就怎么来,我写的这个日历就是用UIScrollView实现的。只是要自己管理一下View的复用。每一天可以用UIControl,每个月份用一个UIView,我这里每个星期也用一个UIView封装起来了。说一下复用,比较常见的复用就是用3个View,在第一个View要移出屏幕的时候,立即把它移动到最后。但是这种方式有个很大的问题,就是无法应对测试同学的暴力活动,通过Instruments检测,addSubviewremoveFromSuperview都是非常耗时的。在用UIScrollView做图片的循环滚动时发现了一种复用方式,避免了去不停的添加和移除View。在滑动在第一个View的边缘或者最后一个View的边缘时,通过设置contentOffsetUIScrollview置到中间位置,更新与View绑定的数据源。这样在视觉效果上还是不停的在滚动,感兴趣的话可以看一下代码

以上都只是自己的一些看法,有不同想法欢迎在评论去留言哦~~

终于写完啦,从动笔写第一段到全文完,拖了好像快1个月啦,拖的我自己都佩服自己了ㄟ( ▔, ▔ )ㄏ