之前公司的设计师在做设计时,提出了一个这样的需求:在网络失败的时候需要展示一张特殊的提示图,类似这样
image
但是当时由于之前项目时间比较紧,程序员们选择性的忽略了这个需求。最近在重新整理项目的代码,忽然想到了这个需求。虽然设计师和PM好像都忘记了这个事情,但是本着通过现有需求完善自己短板漏洞的原则,我还是决定把这个功能实现一下。
需求分析
1.BaseActivity分为需要请求网络的界面,不需要请求网络的界面
2.当网络请求失败时,Title应该保持加载出来的状态
3.当网络请求前,Title上的一些按钮和文本(等其他有需要的View)需隐藏,网络请求成功后需显示
4.网络请求提供Loading设置
要优雅
1.提供是否开启该功能设置
2.提供默认的NoResponseView方案,并暴露出自定义View的接口,提供点击刷新功能
3.提供请求前后的回调方便配置其他属性
4.提供默认的Loading方案,并暴露出自定义LoadingView的接口
5.提供子类,RecycleViewActivity用于列表实现
OK,我们来写代码
拆分title和content
由需求可知,当该界面本身携带标题栏时,网络请求结束前,标题栏仍要正常显示,所以,这里我想到的处理方式时,单独导入标题栏和页面布局,由于目前的界面效果大部分标题栏都是非系统的ActionBar,所以自定义TitleView和自定义ContentView,把titleView和contentView作为子View添加后,再setContentView的方式实例化布局。
所以要实现该功能,要先实现title和content的拆分。
title和content的拆分上一篇博客已提前实现,这里不再赘述。↓↓↓
创建Activity继承TitleActivity
public class RequestActivity extends TitleActivity {
}
定义抽象方法
protected abstract void onInit();
protected abstract int titleLayoutId();
protected abstract int contentLayoutId();
protected boolean createAfterRequestSuccess() {
return false;
}
/**
* 准备网络请求时的布局
*/
protected int prepareRequestView() {
return R.layout.layout_request_prepare;
}
/**
* 当没有响应数据时加载的布局
*/
protected int noResponseView() {
return R.layout.layout_request_fail;
}
/**
* 指定在预加载界面点击刷新的按钮
*/
protected int refreshBtnId() {
return 0;
}
/**
* 开启请求
*/
protected abstract void onRequest();
在onCreate中实现判断逻辑
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitleView(titleLayoutId());
if (!createAfterRequestSuccess()) {
setContentView(contentLayoutId());
onInit();
} else {
int prepare = prepareRequestView();
if (prepare != 0) {
setContentView(prepare);
}
onRequest();
}
}
定义网络请求结束的回调方法
/**
* 网络请求成功后需调用该方法
*/
protected void whenRequestSuccess() {
setContentView(contentLayoutId());
onInit();
}
/**
* 网络请求失败后需调用该方法
*/
protected void whenRequestFail() {
int noResponse = noResponseView();
if (noResponse != 0) {
View view = LayoutInflater.from(thisActivity).inflate(noResponseView(), null);
setContentView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
int refreshBtnId = refreshBtnId();
if (refreshBtnId != 0) {
view.findViewById(refreshBtnId).setOnClickListener(refreshListener);
} else {
view.setOnClickListener(refreshListener);
}
}
}
View.OnClickListener refreshListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int prepare = prepareRequestView();
if (prepare != 0) {
setContentView(prepare);
}
onRequest();
}
};
使用方法
public class TestTitleActivity extends RequestActivity {
private boolean requestFail = true;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setCustomTitle("HaHaHa");// 设置title
}
@Override
protected void onInit() {
}
@Override
protected ITitleStyle titleStyle() {
return new TitleStyleFloatScroll();
}
@Override
protected int titleLayoutId() {
return R.layout.layout_title;
}
@Override
protected int contentLayoutId() {
return R.layout.activity_title_test;
}
@Override
protected boolean createAfterRequestSuccess() {
return true;
}
@Override
protected void onRequest() {
// 延时模拟网络请求
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (requestFail) {
whenRequestFail();
} else {
whenRequestSuccess();
}
requestFail = false;
}
}, 3000);
}
}
最后
代码已发布到github了,我自己的项目也在使用,会根据项目一直更新
顺便还加入了基础的动画效果
https://github.com/mengai60/android-lib
网友评论