热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

写一个多状态View

在app开发过程中很多时候我们需要访问网络,访问数据库等,此时app将会有多种状态,比如加载中,加载成功,加载

在app开发过程中很多时候我们需要访问网络,访问数据库等,此时app将会有多种状态,比如加载中,加载成功,加载失败,没有网络等等,此时如果我们使用弹出的方式告知用户,非常不友好。之前被产品爸爸说有种笨重的感觉,但是笨重这么抽象你告诉我我TM该怎么理解呢? 经过leader的暗示解答,终于知道原来他想要那种感觉,就是那种看起来不笨重的感觉,翻译过来就是使用多状态,那么应该怎么做呢?看到过有人封装在BaseFragment和BaseActivity,但是这样子做耦合度太高,而且看起来代码也比较笨重,是的又回到了笨重这个话题。 ####效果演示 那么笨重feel是怎样的呢?

那么一般我们应该怎么做呢? 看看下面的小图图:
####整体结构 那么它的整体结构是怎样的呢?
从上面的整体结构i图可以知道主要有以下方法:

createView() 构造方法,这里重载了两个,分别使用默认的view以及使用you like view
onLoad() 加载方法,显示loadingview
onEmpty() 空数据,显示emptyView
onError() 加载出错,显示errorView
onNoNet() 没有网络,显示noNetView
onSuccess 加载成功,显示构造方法传入的contentView
onDestory() 资源回收
setOnRetryClick() 提供点击重新加载的接口

####使用 使用方法很简单,根据上面的整体结构

  1. 构造StatusViewManager manager = StatusViewManager.createView(Context, ContentView);
  2. 加载manager.onLoad()
  3. 根据情况调用各种状态

####代码实现 #####StatusViewManager

/*** Created by AmatorLee on 2017/7/12.*/public class StatusViewManager extends StatusInterface implements View.OnClickListener {private LayoutInflater mInflater;/*** 加载view*/private View mLoadView;/*** 错误view*/private View mErrorView;/*** 无数据view*/private View mEmptyView;/*** 实际view*/private View mContentView;/*** 无网络链接时得view*/private View mNoNetView;private RelativeLayout.LayoutParams mParams;/*** 保存状态view的container*/private RelativeLayout mStatusContainer;private Context mContext;/*** 避免重复添加*/private boolean isAddLoad, isAddEmpty, isAddNoNet, isAddError;/*** 可见状态*/public static final int V = View.VISIBLE;/**** 不可见状态*/public static final int G = View.GONE;/*** 重新加载接口*/private onRetryClick mOnRetryClick;/*** 切换到主线程改变view的状态*/private Handler mMainThreadHandler;private int empty_layout_id = -1;private int error_layout_id = -1;private int no_net_layout_id = -1;private int loading_layout_id = -1;public static final String ERROR = "error";public static final String EMPTY = "empty";public static final String NONET = "nonet";public static final String LOAD = "load";public void setOnRetryClick(onRetryClick onRetryClick) {mOnRetryClick = onRetryClick;}private StatusViewManager(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {super();this.loading_layout_id = loading_layout_id;this.empty_layout_id = empty_layout_id;this.error_layout_id = error_layout_id;this.no_net_layout_id = no_net_layout_id;mContentView = contentView;mMainThreadHandler = new Handler(Looper.getMainLooper());mContext = context;mInflater = LayoutInflater.from(context);mParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);mParams.addRule(RelativeLayout.CENTER_IN_PARENT);initView();setOnClick();initContainer();}private void setOnClick() {if (mEmptyView != null)mEmptyView.setOnClickListener(this);if (mNoNetView != null)mNoNetView.setOnClickListener(this);if (mErrorView != null)mErrorView.setOnClickListener(this);}public static StatusViewManager createView(Context context, View ContentView) {return new StatusViewManager(context, ContentView, -1, -1, -1, -1);}public static StatusViewManager createView(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {return new StatusViewManager(context, contentView, loading_layout_id, empty_layout_id, error_layout_id, no_net_layout_id);}@Overrideprotected void initView() {if (loading_layout_id == -1) {loading_layout_id = R.layout.layout_loading;}if (empty_layout_id == -1) {empty_layout_id = R.layout.layout_empty;}if (error_layout_id == -1) {error_layout_id = R.layout.layout_error;}if (no_net_layout_id == -1) {no_net_layout_id = R.layout.layout_no_net;}try {mLoadView = mInflater.inflate(loading_layout_id, null);mLoadView.setTag(LOAD);mErrorView = mInflater.inflate(error_layout_id, null);mErrorView.setTag(ERROR);mEmptyView = mInflater.inflate(empty_layout_id, null);mEmptyView.setTag(EMPTY);mNoNetView = mInflater.inflate(no_net_layout_id, null);mNoNetView.setTag(NONET);} finally {mInflater = null;}}@Overridepublic void initContainer() {mStatusContainer = new RelativeLayout(mContext);mStatusContainer.setLayoutParams(mParams);ViewGroup parent = (ViewGroup) mContentView.getParent();parent.addView(mStatusContainer);}@Overridepublic void onLoad() {mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {if (mLoadView != null && !isAddLoad) {isAddLoad = true;mStatusContainer.addView(mLoadView, mParams);}show(STATUS.LOADING);}});}private void show(STATUS result) {switch (result) {case SUCCESS:changeVisiable(V, G, G, G, G);break;case LOADING:changeVisiable(G, V, G, G, G);break;case NONET:changeVisiable(G, G, G, G, V);break;case ERROR:changeVisiable(G, G, G, V, G);break;case EMPTY:changeVisiable(G, G, V, G, G);break;}}private void changeVisiable(final int contentStatus, final int loadStatus, final int emptyStatus, final int errorStatus, final int nonetStatus) {if (mContentView != null) {mContentView.setVisibility(contentStatus);}if (mLoadView != null) {mLoadView.setVisibility(loadStatus);}if (mEmptyView != null) {mEmptyView.setVisibility(emptyStatus);}if (mNoNetView != null) {mNoNetView.setVisibility(nonetStatus);}if (mErrorView != null) {mErrorView.setVisibility(errorStatus);}}@Overridepublic void onSuccess() {mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {show(STATUS.SUCCESS);}});}@Overridepublic void onNoNet() {mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {if (!isAddNoNet && mNoNetView != null) {mStatusContainer.addView(mNoNetView, mParams);isAddNoNet = true;}show(STATUS.NONET);}});}@Overridepublic void onError() {mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {if (!isAddError && mErrorView != null) {mStatusContainer.addView(mErrorView, mParams);isAddError = true;}show(STATUS.ERROR);}});}@Overridepublic void onEmpty() {mMainThreadHandler.post(new Runnable() {@Overridepublic void run() {if (!isAddEmpty && mEmptyView != null) {mStatusContainer.addView(mEmptyView, mParams);isAddEmpty = true;}show(STATUS.EMPTY);}});}@Overridepublic void onClick(View view) {if (mOnRetryClick != null) {mOnRetryClick.onRetryLoad();}}public enum STATUS {LOADING,EMPTY,ERROR,SUCCESS,NONET}@Overridepublic void onDestory() {isAddNoNet = false;isAddEmpty = false;isAddLoad = false;isAddError = false;mContext = null;if (mLoadView != null) {mLoadView = null;}if (mContentView != null) {mContentView = null;}if (mEmptyView != null) {mEmptyView = null;}if (mErrorView != null) {mErrorView = null;}if (mNoNetView != null) {mNoNetView = null;}if (mParams != null) {mParams = null;}for (int i = 0; i #####StatusInterface

/**

  • Created by AmatorLee on 2017/7/12. */

public abstract class StatusInterface {

protected abstract void initView();protected abstract void initContainer();protected abstract void onLoad();protected abstract void onSuccess();protected abstract void onNoNet();protected abstract void onError();protected abstract void onEmpty();protected abstract void onDestory();

}你可能会问为什么要提供一个StatusInterface```,但是我不告诉你。 ####总结 现在流行的直播平台大都是这个小技巧,虽然简单但是常用,所有自己简单的写一下,如果你发现有bug,尽情反馈,同时我也会自我完善。 最后,provide a gayhub demo



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 本文介绍了如何使用elementui分页组件进行分页功能的改写,只需一行代码即可调用。通过封装分页组件,避免在每个页面都写跳转请求的重复代码。详细的代码示例和使用方法在正文中给出。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
author-avatar
公寓朝仓音梦NQey
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有