从源码上分析ListView/GridView调用setEmptyView不起作用的原因及解决办法
来源:互联网 发布:盛势网络剧哪里可以看 编辑:程序博客网 时间:2024/06/08 02:52
当我们使用ListView或GridView的时候,当列表为空的时候,我们往往需要一个Loading或者一段提示文字又或者一个特殊的View来提示用户操作,这个时候就用到了setEmptyView()方法。
setEmptyView()其实是AdapterView的方法,而我们开发中常用到的ListView, GridView, ExpandableListView等都是继承于AdapterView的,所以可以直接调用这个方法。
但是问题来了,当你这个emptyview不在当前的View hierarchy上,那么你直接调用setEmptyView(emptyview)是不会有任何效果的,为什么呢?请看源码:
/** * Sets the view to show if the adapter is empty */ @android.view.RemotableViewMethod public void setEmptyView(View emptyView) { mEmptyView = emptyView; // If not explicitly specified this view is important for accessibility. if (emptyView != null && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } final T adapter = getAdapter(); final boolean empty = ((adapter == null) || adapter.isEmpty()); updateEmptyStatus(empty); }由上面看到,setEmptyView只是把emptyView赋值到成员变量mEmptyView里,并判断adpater是否为空,进而调用updateEmptyStatus(empty);更新视图,下面再看看updateEmptyStatus(empty)的实现:
/** * Update the status of the list based on the empty parameter. If empty is true and * we have an empty view, display it. In all the other cases, make sure that the listview * is VISIBLE and that the empty view is GONE (if it's not null). */ private void updateEmptyStatus(boolean empty) { if (isInFilterMode()) { empty = false; } if (empty) { if (mEmptyView != null) { mEmptyView.setVisibility(View.VISIBLE); setVisibility(View.GONE); } else { // If the caller just removed our empty view, make sure the list view is visible setVisibility(View.VISIBLE); } // We are now GONE, so pending layouts will not be dispatched. // Force one here to make sure that the state of the list matches // the state of the adapter. if (mDataChanged) { this.onLayout(false, mLeft, mTop, mRight, mBottom); } } else { if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); setVisibility(View.VISIBLE); } }这里大概的逻辑就是判断如果adapter为空,则把mEmptyView的visible属性改为显示,否则把listview显示。从这里看出来,setemptyview不会把emptyviw add到当前的view hierarchy上,而当前界面只是显示当前的view hierarchy的,所以如果这个emptyview不在当前的View hierarchy上,那么你直接调用setEmptyView(emptyview)是不会有任何效果的。
问题根源我们找到了,那么我们该怎么解决呢?那就是把这个emptyview加入到当前view hierarchy上咯,对此有两种方法可以实现:
1. Empty View和ListView在同一个布局文件里
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/list_view" /> <TextView android:id="@+id/tv_empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Loading data..." /></FrameLayout>ListView listView = (ListView)findViewById(R.id.list_view);listView.setEmptyView(findViewById(R.id.tv_empty));
2. Empty View在单独的布局文件里,这种一般适用于比较复杂的View或者打算在多个地方复用
setEmptyView()这个方法是有限制的,这个View必须在当前的View hierarchy的节点上,所以当我们写在外面单独的布局文件里时,需要把View添加到当前的View hierarchy的节点上。所以就需要下面的用法:
View emptyView = View.inflate(R.layout.empty_view, null);((ViewGroup)list.getParent()).addView(emptyView);ListView listView = (ListView)findViewById(R.id.list_view);listView.setEmptyView(emptyView);
有些同学可能说,不对啊,我调用的setemptyview不用要求这个View必须在当前的View hierarchy的节点上啊,为什么我的运行好好的?
答:那你一定是使用了第三方的控件,它里面重写了setemptyview。比如著名的PullToRefresh 中的PullToRefreshAdapterViewBase的setemptyView实现如下:
public final void setEmptyView(View newEmptyView) {FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();if (null != newEmptyView) {// New view needs to be clickable so that Android recognizes it as a// target for Touch EventsnewEmptyView.setClickable(true);ViewParent newEmptyViewParent = newEmptyView.getParent();if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {((ViewGroup) newEmptyViewParent).removeView(newEmptyView);}// We need to convert any LayoutParams so that it works in our// FrameLayoutFrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams());if (null != lp) {refreshableViewWrapper.addView(newEmptyView, lp);} else {refreshableViewWrapper.addView(newEmptyView);}}if (mRefreshableView instanceof EmptyViewMethodAccessor) {((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);} else {mRefreshableView.setEmptyView(newEmptyView);}mEmptyView = newEmptyView;}
注意refreshableViewWrapper.addView(。。)就把emptyview添加了进去。
/** * setEmptyView()方法需要把空View放在当前layout中,才起作用; * 而setEmptyLayout()方法则不需要(自己添加的方法) * @param emptyView */ public void setEmptyLayout(View emptyView) { this.mEmptyView = emptyView; ViewParent parent = this.getParent(); if (parent != null && parent instanceof ViewGroup) { ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ((ViewGroup) parent).addView(mEmptyView, layoutParams); } mDataObserver.onChanged(); }
阅读全文
0 0
- 【android】从源码上分析ListView/GridView调用setEmptyView不起作用的原因及解决办法
- 【android】从源码上分析ListView/GridView调用setEmptyView不起作用的原因及解决办法
- 从源码上分析ListView/GridView调用setEmptyView不起作用的原因及解决办法
- ListView.setEmptyView不起作用
- 从源码上分析ListView的addHeaderView和setAdapter的调用顺序
- ListView与GridView中SetEmptyView方法的使用,及触发条件
- android 从源码分析为什么Listview初次显示时没滚动却自动调用onScroll方法的原因
- ListView.setOnItemClickListener不起作用的原因
- 解决ListView列表setEmptyView无效问题及源码解析
- Android listview的setemptyview
- ListView的onItemClickListener不起作用解决办法
- layout_gravity不起作用的原因分析
- ListView的setSelection()不起作用的原因
- android listview notifyDataSetChange(),不起作用的可能原因
- ListView和GridView多次调用GetView的现象和解决办法
- ListView和GridView多次调用GetView的现象和解决办法
- ListView之setEmptyView的问题
- ListView之setEmptyView的问题
- 3504: [Cqoi2014]危桥
- JPA通过方法名实现模糊查询
- SqlServer数据库的备份与还原
- java 实现 简易的base64(byte[]与String的相互转换)
- 百度前端作业-01
- 从源码上分析ListView/GridView调用setEmptyView不起作用的原因及解决办法
- 随机梯度下降和批量梯度下降的区别
- Linux运维 -- day04 常用命令
- df命令出现的xvda1的意思
- HDU 2586 How far away ? LCA离线tarjan思想
- 如何限制网页只能在微信内置浏览器中打开?
- MyEclipse不能打开文件问题
- X.805安全体系框架
- 精通比特币