前言
Android项目不管使用什么框架结构,承载界面的必然少不了Activity或者Fragment,而对于一个用户界面来说,有一些业务逻辑的处理是通用的,比如请求网络时需要有loading框,比如网络错误时需要界面有对应提示,比如通用的导航栏,比如每个界面都用activity就需要在Manifest.xml文件中配置等等,这些能否做一些封装,可以让开发者只关注具体界面的具体逻辑,快速的实现一个界面?
思考方向
基于以上的问题,我们要封装的内容需要满足以下需求:
- 不用每一个用户界面都在Manifest.xml文件中配置
- 通用的导航栏处理
- 通过简单的继承就可以自动实现loading(这个后续还会和网络请求关联)、异常界面(没数据、无网络等)显示等
用户界面的承载选择
如果想不在Manifest.xml中配置很多用到的用户界面,那么使用Fragment就是我们的必然选择了,使用Fragment有两种方式,一种是所有的Fragment都有一个公用的Activity来承载,每一次用户切换界面其实还是切换Activity,第二个就是只启动一个Activity,在Activity中切换Fragment以达到界面的切换。第二种看起来更合理一点,但是对于界面生命周期的管理以及一些公用的参数用不好就会出现混乱的情况,所以我们采用第一种方案。
方案思路
先定义一个接口,封装基本的界面操作方法(loading、toast、显示错误信息等),然后用一个BaseFragment来实现该接口方法,在用一个activity来承载这个实现了BaseFragment的不同Fragment,传递的参数中告诉Activity需要加载的Fragment名字,通过这样,只需要注册一个承载Acitivty就可以实现显示不同的用户界面。如下图:
具体实现
按照上面思路首先要定义好一个用户界面基本的方法
- IView.java 在MVP模式中也会复用到
package com.kotlin.anonyper.testapplication.base;
/**
* 普通view的操作接口
* TestApplication
* Created by anonyper on 2018/12/17.
*/
public interface IView {
/**
* 弹出通知
*
* @param message
*/
void showToast(String message);
/**
* 隐藏loading条
*/
void hideLoading();
/**
* 控制显示loading
*
* @param message loading内容
* @param cancelAble 是否可取消
*/
void showLoading(String message, boolean cancelAble);
/**
* 显示内容部分view
*/
void showContentView();
/**
* 显示异常部分view
*
* @param imageRes 显示的资源图片
* @param message 显示的信息
*/
void showExcptionView(int imageRes, String message);
}
然后用Fragment来实现IView接口,实现其中的方法
/**
* 基本的fragment
* TestApplication
* Created by anonyper on 2018/12/18.
*/
public abstract class BaseFragment extends Fragment implements IView {
private ProgressDialog progressDialog;
@Override
public void showToast(String message) {
Toast.makeText(this.getContext(), message, Toast.LENGTH_LONG).show();
}
@Override
public void hideLoading() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
@Override
public void showLoading(String message, boolean cancelAble) {
if (TextUtils.isEmpty(message)) {
message = "";
}
if (progressDialog == null) {
progressDialog = new ProgressDialog(this.getActivity());
}
if (this.getActivity().isFinishing()) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (this.getActivity().isDestroyed()) {
return;
}
}
progressDialog.setMessage(message);
progressDialog.setCanceledOnTouchOutside(true);
progressDialog.setCancelable(cancelAble);
if (!progressDialog.isShowing()) {
progressDialog.show();
}
}
@Override
public void showContentView() {
}
@Override
public void showExcptionView(int imageRes,String message) {
}
}
上述中showContentView
和showExcptionView
没有具体的实现,这个会放到BaseFragment的子类中来实现。
针对大多数用户界面(带有网络请求),有一个同样式的title导航、异常界面以及数据界面切换显示逻辑。针对这种情况,我们封装一个SimpleBaseFragmen,将显示内容和异常界面用FrameLayout容器并列存放,然后和导航栏的view通过LinearLayout容器竖直排列。先看公用的title类:
/**
* 公共标题
*/
public class TitleBar extends RelativeLayout {
Context mContext;
View titleView;
@BindView(R.id.imgv_titleleft)
ImageView imgvTitleleft;
@BindView(R.id.rlt_titleleft)
RelativeLayout rltTitleLeft;
@BindView(R.id.tv_title)
TextView tvTitle;
@BindView(R.id.imgv_