现在绝大多数 App 都需要请求网络数据,loading 动画必不可少,而网络请求会存在失败的情况,所以通常有 loading 页面也会有加载失败或者别的页面。
这些页面的样式大多时候是统一的,一般会想到的处理方式是把这些界面 include 到一个布局里,然后通过显示隐藏的方式来切换所需的视图。不过总是会写很多重复代码,可能会想到把这部分切换的逻辑抽取到 Activity 基类中或者抽取到一个自定义 View 里管理。
不过这些封装都不能解决本身存在的问题。不方便修改样式,样式有变动就需要修改已经封装好的代码。总要在布局上增加 include 代码或添加一个处理切换界面的自定义 View,多多少少有些冗余。
优化思路
灵活地配置所需视图
我们不能把需要展示的控件写死了,所以要把 View 的创建解耦出来,然后动态添加到父容器里进行管理。那么如何解耦呢?可以参考 Android 中 ListView 或 RecyclerView,都是通过 Adapter 来实现 View 的创建和数据绑定。不过如果参考列表的用法只设置一个 Adapter,我们就要在创建视图的方法里做很多的判断,一种类型就对应一个视图,这样写起来就不是很方便,所以建议拆分成多个适配器进行配置。
减少布局冗余的代码
每个布局都要增加相同的代码,那么有没有什么办法能把这一步都省掉呢?这就要先提一下 ActionBar,不知道有没人好奇在布局文件里没写任何 ActionBar 相关的控件却能生成 ActionBar,有兴趣的可以自行了解下 DecorView 源码,就不继续展开了。这里采用生成 ActionBar 同样的思路,其实算是一波偷天换日的操作,将原有的视图换成了一个我们需要的容器,再把视图添加到容器中。
decorView = new LinearLayout(contentView.getContext());
decorView.setOrientation(LinearLayout.VERTICAL);
decorView.setLayoutParams(contentView.getLayoutParams());
ViewGroup parent = (ViewGroup) contentView.getParent();
if (parent != null) {
int index = parent.indexOfChild(contentView);
parent.removeView(contentView);
parent.addView(decorView, index);
}
复制代码解决方案
LoadingHelper 是基于 Adapter 思想 和 ActionBar 原理实现的一个用于显示加载界面的的拓展性高、耦合低的工具,只用了一个 200 行左右的 Kotlin 代码实现(不包含注释)。
基础用法
在 build.gradle 添加依赖:
dependencies {
implementation ‘com.dylanc:loadinghelper:1.1.0’
}
复制代码第一步,创建一个适配器继承 LoadingHelper.Adapter,写法与 RecyclerView.Adapter 类似。如果需要实现点击重新请求数据,可以在点击事件调用 holder.getOnReloadListener.onReload() 方法。
public class LoadingAdapter extends LoadingHelper.Adapter<LoadingHelper.ViewHolder> {
@NonNull
@Override
public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGrou