Android空数据页面提示控件
来源:互联网 发布:阿里云短视频sdk 编辑:程序博客网 时间:2024/04/27 16:56
前言
通常,当我们的应用页面没有数据可以显示时,我们需要给予用户一些界面提示,以避免空空如也的页面带来较差的用户体验。一般这样的页面都为ListView, ListView 很贴心的提供了
setEmptyView(View emptyView);
方法来保证用户体验,但是如果你有2年以上的开发经验,你肯定知道,系统的原生控件是永远都满足不了需求的。 setEmptyView 的Bug之一:一般来说现在的应用ListView都会配备下拉刷新,那么当下拉刷新时,ListView是要被清空的,所以你会发现:空数据提示信息忽隐忽现。再者,当刚进页面,数据还没有加载完成时,空数据提示信息已经显示了,当数据加载完之后空数据提示信息又隐藏,说实话,这样的体验真的很差,你应该没有看到哪个应用的效果是这样的吧?
那么好,今天带来的一个自定义控件,就是为了解决这个需求的,同时,它不止满足于ListView,可以应对所有你想出现的页面。
首先看下效果
`
在看代码之前,要说一个开发的技巧:避免相同一段逻辑重复出现两次以上,当一段逻辑代码出现2次以上,你很难保证将来它不会出现3次,4次 ,10次。
所以去规范你的代码,让你的类、方法单一。既可以调高代码可读性,维护性,又可以实现代码复用,最重要的,你的代码可测试了。
实现的技巧:将你的代码按照数据接收、数据转换、逻辑判断、数据输出等进行区分,放到不同方法里。下面的代码算是一个实现,虽然有很多的重载方法,但是你看不到相同的逻辑代码段,修改时,只需要修改一个方法就好了,不需要去每个地方改。
看下类结构:
然后看代码,先自定义控件的实现。判断一个ListView是否为空,可以通过数据集和Adapter来判断,所以这里写了几个重载方法接收数据集或Adapter。
Message的作用是判断是否什么原因导致无数据的:数据库空、无网络、服务器请求失败。
如果你有不同的需求,只要继承这个类,实现你自己的方法就OK。
/** * Created by zhaoxuan.li on 2015/8/28. * 无数据时提示的自定义控件 */public class NoDataTipsWidget extends RelativeLayout { protected static final int TASK_COMPLETED = 1;//网络请求成功 protected static final int TASK_FAILED = -1;//服务器连接失败 protected static final int TASK_NONETWORK = -2;//无网络 private ImageView tipImage; private TextView tipText; public TipsOnClickListener tipsOnClickListener;public NoDataTipsWidget(Context context) { super(context); init(context, null);}public NoDataTipsWidget(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs);}/** * 对控件进行初始化,并取得xml文件里给予的资源 * @param context * @param attrs */private void init(Context context, AttributeSet attrs){ if(attrs ==null) return; LayoutInflater.from(context).inflate(R.layout.nodata_tipsview, this, true); tipImage = (ImageView)findViewById(R.id.tipImage); tipText = (TextView)findViewById(R.id.tipText); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NoDataTipsWidget); CharSequence text = a.getText(R.styleable.NoDataTipsWidget_android_text); if(text!=null) tipText.setText(text); Drawable drawable = a.getDrawable(R.styleable.NoDataTipsWidget_android_src); if(drawable != null) tipImage.setImageDrawable(drawable); a.recycle(); //设置图片的点击事件,通常我们在这里设置点击图片刷新 tipImage.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (tipsOnClickListener != null) tipsOnClickListener.OnClick(); } });}/** * 设置提示图片的监听事件,一个事件接口,需要调用处来实现 * @param onClickListener */public void setTipsClickListener(TipsOnClickListener onClickListener){ tipsOnClickListener = onClickListener;}/** * 设置提示文字 * @param str */public void setText(String str){ tipText.setText(str);}/** * 设置提示图片 * @param drawable */public void setImage(Drawable drawable){ tipImage.setImageDrawable(drawable);}/** * 图片点击事件回调接口 */public interface TipsOnClickListener{ void OnClick();}/** * 重載方法,當無Adapter可以加入時,使用List判斷 * @param msg handler Message * @param dto List 数据集 */public void doTipsView(Message msg , List dto){ doTipsView(msg, isEmpty(dto));}/** * 重載方法 仅根据List 数据集判断提示样式 * @param dto List 数据集 */public void doTipsView(List dto){ doTipsView(null,isEmpty(dto));}/** * 重載方法 仅根据Adapter设置提示样式 * @param adapter Adapter */public void doTipsView(Adapter adapter){ doTipsView(null,isEmpty(adapter));}/** * 根据 Message 和 Adapter 设置提示样式 * @param msg handler Message * @param adapter Adapter 数据集 */public void doTipsView(Message msg , Adapter adapter){ doTipsView(msg, isEmpty(adapter));}/** * 重载方法仅用于数据接收,具体的判断逻辑由此方法统一处理 * @param msg * @param noData */private void doTipsView(Message msg , boolean noData){ if(!noData){ //如果数据集不为空,就隐藏 this.setVisibility(View.GONE); return ; }else{ if(msg==null){ showTip_noData(); return; } switch (msg.what){ case TASK_COMPLETED: //网络请求成功 showTip_noData();return; case TASK_FAILED: //网络请求失败 showTip_noServer();return; case TASK_NONETWORK: showTip_noConnect();return; } }}private boolean isEmpty(Adapter adapter){ if(adapter == null) return true; return adapter.isEmpty();}private boolean isEmpty(List list){ if(list == null) return true; return list.isEmpty();}/** * 设置样式为无数据样式 */public void showTip_noData(){ tipImage.setImageResource(R.drawable.nodatatip_nodata); tipText.setText("无任何数据"); this.setVisibility(View.VISIBLE);}/** * 设置样式为无连接样式 */public void showTip_noConnect(){ tipImage.setImageResource(R.drawable.nodatatip_noserver); tipText.setText("无网络连接"); this.setVisibility(View.VISIBLE);}/** * 设置样式为无服务器样式 */public void showTip_noServer(){ tipImage.setImageResource(R.drawable.nodatatip_noserver); tipText.setText("暂时无法连接服务器,请稍后再试"); this.setVisibility(View.VISIBLE);}}
实际上就是一个继承相对布局的View,只不过这个View可以自己控制自己是否显示。View的布局文件很简单一个ImageView一个TextView,这里就不放了。
注释已经写得很清楚了,这里不在详细解释。
另外需要在你要的布局里引入控件:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin"android:background="#436EEE"tools:context=".MainActivity"><ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" /><com.example.zhaoxuanli.nodatatipdemo.widget.NoDataTipsWidget android:id="@+id/nodata_tipsview" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"/>
这里有一个限制,就是根布局只能是相对布局或帧布局
Activity中引用。一般情况下,noDataTipsView.doTipsView(msg, list);的调用处实在 数据接收完毕后,或刷新处调用。
目的就是给noDataTipsView最新的数据集让他判断。
public class MainActivity extends AppCompatActivity { protected static final int TASK_COMPLETED = 1; //网络请求成功 protected static final int TASK_FAILED = -1; //服务器连接失败 protected static final int TASK_NONETWORK = -2;//无网络private NoDataTipsWidget noDataTipsView;/** * 因为是一个简单的Demo,空数据提示是肯定要显示的,ListView我们也用不到,就不初始化了 * @param savedInstanceState */@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); noDataTipsView = (NoDataTipsWidget)findViewById(R.id.nodata_tipsview); new Timer().schedule(new TimerTask() { @Override public void run() { handler.sendEmptyMessage(-1);// 测试是请求失败的情况 } }, 2000);// 延迟1秒,然后加载}Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { ArrayList list = new ArrayList(); //List是空的,所以应该显示空数据提示 switch (msg.what){ case TASK_COMPLETED: //请求成功后处理 break; case TASK_FAILED: //请求失败后处理 break; case TASK_NONETWORK: //无网络情况处理 break; } //所有状况处理完毕后,调用noDataTipsView.doTipsView()方法 adapter 或List都可以 noDataTipsView.doTipsView(msg, list); };};
}
最后是源代码 :http://download.csdn.net/detail/u010255127/9198155
- Android空数据页面提示控件
- Android之RecyclerView之空数据提示
- Android 自定义空数据提示界面 EmptyView
- Android之RecyclerView之空数据提示
- iOS开发之UITableView数据为空的提示页面
- android 过渡和空数据页面
- 清空页面控件值
- Android-->打造流行的无数据空布局页面
- android 登陆、提交数据或加载数据时提示页面
- android 登陆、提交数据或加载数据时提示页面
- android 登陆、提交数据或加载数据时提示页面
- android 登陆、提交数据或加载数据时提示页面
- android 控件空应用
- 空页面的背景提示原理
- Android自定义的控件在eclipse中提示空指针但是在程序中跑起来没问题
- 清空页面控件的输入
- JS清空页面控件的值
- 遍历清空页面控件的值
- Android定位入门(1)了解定位管理器--LocationManager 类
- 2015/10/20 类似UItarBarController 界面 设计 微博项目 自定义键盘
- ZOJ - 1610 Count the Colors(线段树)
- [Django模板系统]Django模板的include机制
- 自定义LinkedList
- Android空数据页面提示控件
- Eclipse与Mysql驱动连接的问题
- Android 新特性 - TabLayout
- 技术小故事-Activity的Launch Mode引起的动画“疑案”
- HDOJ 动态规划总结
- php 匹配字符串中的连续数字
- HDU 1466 DP
- 云计算服务模型,第 1 部分: 基础架构即服务(IaaS)
- 单链表的Java实现