需求
在项目开发的过程中,需要对Api的数据的不同情况反映到UI界面上,以达到良好的用户体验,Api的数据的状态大致可分为异步请求数据、正常返回数据、空数据、加载失败、网络错误等一些状态,相应的布局状态也可分为加载中、正常显示、无数据、加载出错等状态,于是就有了对多状态布局进行管理的需求。
在早期这个需求刚被提出来的时候,最开始的做法是使用FrameLayout或LinearLayout布局里面嵌套对应状态的xml布局,在各种状态布局切换时,需要在Activity或Fragment里使用java代码频繁的调用各种view的显示与隐藏(小白的做法),最后这样做出来造成代码臃肿,操作繁琐,而且不可复用,最后不得不重构,于是就有了EmptyLayout多状态布局。
父容器的选择
基于布局特点、扩展性、性能方面考虑,RelativeLayout由于在 layout 时需要 measure 两次被忽略,LinearLayout也可以作为父布局,不过FrameLayout的层次的特性更适合,比如在空布局状态时需要在顶部显示另外的view的情况下,如下图所示
定义过程
首先为各种布局状态定义标志位
接着在 attrs.xml 中定义自定义属性,用于配置在不同状态页的默认属性xml然后在初始化的时候通过 TypedArray 进行赋值
类内部维护一个View的List 的集合,为非正常布局各定义一个Tag
重写FrameLayout的 addView 方法把非正常布局过滤
然后在切换布局时把Tag设置到对应的View,比如`setErrorView
最后在对外开放一个接口,提供错误重试的回调
这样一来就把各个布局状态的切换操作封装到自定义组合的Layout中了,只需要对外开放api就行了
其中的skipId是上图中需要在空数据状态下显示的view的Id的集合。基于LinearLayout的使用场景比较多,我还实现了LinearEmptyLayout简版多状态切换的Layout,详细的代码以及Sample可以去我的github查看,觉得还可以的不妨Star或follow
思考
EmptyLayout虽然已经有了很多的应用场景,但是如果你的页面是基于RecyclerView写的,本着避免view嵌套的原则,利用修饰者模式,可以为RecyclerView定义一个EmptyWapper的Adapter,通过Adapter的type控制空页面和错误页面切换。