- 在項目開發(fā)中如何快速處理網(wǎng)絡(luò)加載中錯誤頁面、空數(shù)據(jù)頁面捺檬、網(wǎng)絡(luò)異常等頁面蒿秦?
- 在項目開發(fā)中如何快速實現(xiàn)“上拉刷新”與“加載更多”职车?
過去做法:
-
NetFragment 處理網(wǎng)絡(luò)加載的頁面
- 采用“約定優(yōu)于配置原則”,直接規(guī)定好錯誤頁面、空數(shù)據(jù)頁面茫孔、網(wǎng)絡(luò)異常等頁面的Id
- NetFragment負(fù)責(zé)加載數(shù)據(jù)、控制錯誤頁面锣咒、空數(shù)據(jù)頁面、網(wǎng)絡(luò)異常頁面顯示隱藏
-
ListNetFragment處理下拉刷新和加載更多的界面
- 處理下拉刷新和加載更多的邏輯
- 控制加載數(shù)據(jù)、控制錯誤頁面戏蔑、空數(shù)據(jù)頁面、網(wǎng)絡(luò)異常頁面顯示隱藏
存在的問題:
- 下拉刷新如果失敗候味,listview上面的headView需要保留(不能實現(xiàn))
- 下拉刷新加載過程中,上拉刷新出現(xiàn)崩潰Bug
- 控制邏輯C和頁面展示V 沒有真正分離,可擴展性差
現(xiàn)在做法:
- 剝離網(wǎng)絡(luò)加載控制邏輯
- 從NetFragment中抽取NetController粱玲,處理網(wǎng)絡(luò)加載控制邏輯
從ListNetFragment中抽取ListNetController卵沉,處理下拉刷新和加載更多的邏輯
重寫NetFragment史汗,實現(xiàn)NetController與各種頁面的綁定
重寫ListNetFragment瓷蛙,實現(xiàn)ListNetController與各種頁面的綁定
資源下載:
使用教程
1. NetFragment
- 繪制Xml eg:fragment_exam
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/net_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
//加載中 id為net_progress
<LinearLayout
android:id="@+id/net_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<ProgressBar
style="?android:attr/progressBarStyle"
android:layout_width="200dip"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateOnly="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="數(shù)據(jù)正在加載中……"
android:textColor="#000000" />
</LinearLayout>
//數(shù)據(jù)為空的界面 id為net_no_result
<TextView
android:id="@+id/net_no_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="數(shù)據(jù)為空"
android:textColor="#000000" />
//數(shù)據(jù)錯誤 id為net_error
<TextView
android:id="@+id/net_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="數(shù)據(jù)出錯"
android:textColor="#000000" />
//參數(shù)錯誤 id為net_fail
<LinearLayout
android:orientation="vertical"
android:id="@+id/net_fail"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/nonata_2"/>
</LinearLayout>
//網(wǎng)絡(luò)異常 id為net_cannot_access
<LinearLayout
android:orientation="vertical"
android:id="@+id/net_cannot_access"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/nonata_2"/>
</LinearLayout>
//有數(shù)據(jù) id為net_result
<LinearLayout
android:orientation="vertical"
android:id="@+id/net_result"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/nonata_2"/>
</LinearLayout>
</FrameLayout>
- 網(wǎng)絡(luò)加載的Fragment繼承NetFragment eg: ExamFragment
public class ExamFragment extends NetFragment<GetSelfOfficialExamNameNetResultInfo> {
private static final String TAG = ExamFragment.class.getSimpleName();
@Bind(B.id.nav_go_back)
ImageView navGoBack;
@Bind(B.id.nav_tv_title)
TextView navTvTitle;
@Bind(B.id.nav_tv_right)
TextView navTvRight;
@Bind(B.id.tv_exam_choose_1)
TextView tvExamChoose1;
@Bind(B.id.tv_exam_choose_2)
TextView tvExamChoose2;
@Bind(B.id.ll_item_0)
LinearLayout llItem0;
@Bind(B.id.ll_item_1)
LinearLayout llItem1;
@Bind(B.id.tv_item_0_name)
TextView tvItem0Name;
@Bind(B.id.tv_item_1_name)
TextView tvItem1Name;
private GetSelfOfficialExamNameNetResultInfo resultInfo;//網(wǎng)絡(luò)請求的數(shù)據(jù)模型
/**
* 獲取布局Id
*/
@Override
public int getLayoutId() {
return R.layout.fragment_exam;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = super.onCreateView(inflater, container, savedInstanceState);
navGoBack.setVisibility(View.INVISIBLE);
navTvTitle.setText("考點兒");
navTvRight.setText("考試管理");
return rootView;
}
/**
* 網(wǎng)絡(luò)請求
*/
@Override
public GetSelfOfficialExamNameNetResultInfo onDoInBackgroundSafely() {
GetSelfOfficialExamNameNetResultInfo.Request params = new GetSelfOfficialExamNameNetResultInfo.Request();
return RepositoryCollection.getSelfOfficialExamName(params);
}
/**
* 請求成功時
*/
@Override
protected void onDisplayResult(GetSelfOfficialExamNameNetResultInfo resultInfo) {
this.resultInfo = resultInfo;
tvItem0Name.setText(resultInfo.getSelfExamName());
tvItem1Name.setText(resultInfo.getOfficialExamName());
}
}
2 ListNetFragment 的使用
- 繪制XML eg: fragment_teacher
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/net_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<ListView
android:id="@+id/net_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/width_720_1280_20"
android:layout_marginRight="@dimen/width_720_1280_20"
android:background="@color/bg_window"
android:clipToPadding="false"
android:divider="@color/color_underline"
android:dividerHeight="@dimen/hs1" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
- 繪制異常界面的Xml 作為ListView的item eg:net_list_abnormal_layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/net_no_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/hs200">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:clickable="false"
android:gravity="center"
android:text="@string/net_no_result"
android:textColor="#000000" />
</LinearLayout>
<LinearLayout
android:id="@+id/net_error"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/hs200">
<include layout="@layout/nonata_2" />
</LinearLayout>
<LinearLayout
android:id="@+id/net_fail"
android:layout_width="match_parent"
android:layout_height="match_parent"
ndroid:orientation="vertical"
android:paddingTop="@dimen/hs200">
<include layout="@layout/nonata_2" />
</LinearLayout>
<LinearLayout
android:id="@+id/net_cannot_access"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/hs200">
<include layout="@layout/nonata_2" />
</LinearLayout>
</FrameLayout>
- 繼承ListNetFragment
public class TeacherFragment extends ListNetFragment<AppArticleModel> {
private static final String TAG = TeacherFragment.class.getSimpleName();
@Bind(B.id.nav_go_back)
ImageView navGoBack;
@Bind(B.id.nav_tv_title)
TextView navTvTitle;
@Bind(B.id.iv_teacher_photo)
ImageView ivTeacherPhoto;
@Bind(B.id.tv_teacher_name_1)
TextView tvTeacherName1;
@Bind(B.id.tv_teacher_name_2)
TextView tvTeacherName2;
@Bind(B.id.tv_teacher_name_3)
TextView tvTeacherName3;
@Bind(B.id.ll_log_status)
LinearLayout llLogStatus;
private int teacherId;
private DisplayImageOptions options;
private AppTeacherModel teacherModel;
@Override
public int getLayoutId() {
return R.layout.fragment_teacher;
}
// 獲取網(wǎng)絡(luò)異常 空數(shù)據(jù) 等界面布局
@Override
public int getAbnormalViewLayoutId() {
return R.layout.net_list_abnormal_layout;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = super.onCreateView(inflater, container, savedInstanceState);
// mNetController.setPageSize(20); // 設(shè)置每次加載個數(shù) 默認(rèn)為10
mNetController.addHeadView(headView); // 添加頭布局 沒有可以不寫
mNetController.setListAdapter(); // 注: 在addHeadView(headView)之后箩兽,
// mNetController.setRefreshEnable(false); //能否下拉刷新 默認(rèn)為true
// mNetController.setLoadMoreEnable(false);//能否加載更多 默認(rèn)為true
return rootView;
}
@Override
protected ListNetResultInfo<AppArticleModel> onDoInBackgroundSafely(int i, int i1) {
GetTeacherInfoNetResultInfo.Request params = new GetTeacherInfoNetResultInfo.Request();
PageModel pageModel = new PageModel();
pageModel.setStartIndex(i);
pageModel.setPageSize(i1);
params.setPage(pageModel);
params.setTeacherId(teacherId);
return RepositoryCollection.getTeacherInfo(params);
}
// list item任意一TextView的Id
@Override
public int getItemTextViewResourceId() {
return R.id.tv_content;
}
//list item的布局
@Override
public int getItemLayoutId() {
return R.layout.item_list_teacher;
}
//用于 處理list的item
@Override
public View bindView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
view = View.inflate(getContext(), R.layout.item_list_teacher, null);
}
holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder(view);
view.setTag(holder);
}
final AppArticleModel model = getItem(i);
holder.tvContent.setText(model.getTitle());
String shareTime = TimeUtil.longToString(model.getCreateDate(), TimeUtil.FORMAT_DATE);
holder.tvShareTime.setText(shareTime);
holder.tvPreview.setText("" + model.getViewNum());
return view;
}
class ViewHolder {
@Bind(B.id.tv_title)
TextView tvTitle;
@Bind(B.id.tv_content)
TextView tvContent;
@Bind(B.id.tv_share_time)
TextView tvShareTime;
@Bind(B.id.tv_preview)
TextView tvPreview;
@Bind(B.id.tv_item_teacher_zambia)
TextView tvItemTeacherZambia;
@Bind(B.id.ll_item)
LinearLayout ll_item;
ViewHolder(View view) {
ButterFork.bind(this, view);
}
}
}
解決SwipeRefreshLayout與ViewPager 的滑動沖突
通過重寫SwipeRefreshLayout的onInterceptTouchEvent方法
public class BannerSwipeRefreshLayout extends SwipeRefreshLayout {
public BannerSwipeRefreshLayout(Context context) {
super(context);
}
public BannerSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
float lastx = 0;
float lasty = 0;
boolean ismovepic = false;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
lastx = ev.getX();
lasty = ev.getY();
ismovepic = false;
return super.onInterceptTouchEvent(ev);
}
final int action = MotionEventCompat.getActionMasked(ev);
int x2 = (int) Math.abs(ev.getX() - lastx);
int y2 = (int) Math.abs(ev.getY() - lasty);
//滑動圖片最小距離檢查
if (x2 > y2) {
if (x2 >= 100) ismovepic = true;
return false;
}
//是否移動圖片(下拉刷新不處理)
if (ismovepic) {
return false;
}
boolean isok = super.onInterceptTouchEvent(ev);
return isok;
}
}