以前一直不知道emptyview的存在,觉得像qq那些 无数据时显示的效果很好,想来想去找不到办法实现那样的效果。后来在一个群问时,有人回答 adapterview 有个方法setEmptyView(),就可以设置无数据的提示效果.才知道实现这个效果很简单
后来项目中需要添加无数据时的提示效果, 大多是使用动态加载。使用动态添加在初始化时加入进去就可以满足一般的情况了(qq的消息列表好像这样就可以了)。 TextView textView = new TextView(getBaseContext());
<span style="font-size:18px;"> textView.setText("当前分类无可配送门店,请更换其他分类");
textView.setGravity(Gravity.CENTER);
textView.setVisibility(View.GONE);
textView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
((ViewGroup) listview.getParent()).addView(<span style="font-family: Arial, Helvetica, sans-serif;">textView</span><span style="font-family: Arial, Helvetica, sans-serif;">);</span><span style="font-family: Arial, Helvetica, sans-serif;"> </span>
listview.setEmptyView(no_classfication_tv);</span>
写到这突然想到了,以前反编译一些app,像58、赶集 都是将网络错误、无数据提示的布局include到当前activity的布局里,这就是接下来说要使用到的方式。
首先说遇到的问题吧,动态加载只在初始化时是没有问题的,因为只将emptyview添加了一次到listview的parent里,项目中的所遇到的情况是在数据请求返回后根据结果去设置不同的emptyview,于是我把上面那段代码 放到每次请求后调用,这时问题就来了,每次执行那段代码都会将一个emptyview 添加进去。
看了下addView()的代码
<span style="font-size:18px;"> /**
* Adds a child view. If no layout parameters are already set on the child, the
* default parameters for this ViewGroup are set on the child.
*
* @param child the child view to add
*
* @see #generateDefaultLayoutParams()
*/
public void addView(View child) {
addView(child, -1);
}</span>
后面 还有就不看了.所以这种方法就不太好,如果有多种emptyview,处理起来就麻烦了。
还有一种实现形式,就是在布局里,include layout 然后设置显示属性为gone,为什么要这么设,之后再说,这样不用每次都动态添加到adapterview的父布局里了,
代码里只需要调用adapterview.setEmptyView(View) 就可以了,我在当前adapterview的父布局里加了两个emptyview,然后根据数据请求结果带调用 adapterview.setEmptyView(View) .问题又来了,如果设置了两种emptyview后,有一种会一直显示,这是为什么呢?
接下来就要看adapterview.setEmptyView(View)的代码了
<span style="font-size:18px;"> /**
* Sets the view to show if the adapter is empty
*/
@android.view.RemotableViewMethod
public void setEmptyView(View emptyView) {
mEmptyView = emptyView;
final T adapter = getAdapter();
final boolean empty = ((adapter == null) || adapter.isEmpty());
updateEmptyStatus(empty);
}</span>
我们看到该方法最后调用的是
<span style="font-size:18px;"> updateEmptyStatus(empty);</span>
传入的是个boolean值 ,adapter为null或者为空时 为true
接着看
<span style="font-size:18px;"> updateEmptyStatus(empty);</span>
<span style="font-size:18px;"> /**
* 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);
}
}</span>
<span style="font-size:18px;"> boolean isInFilterMode() {
return false;
}</span>
第一个if 不用管 返回的是false 所以不会改变empty的值
下面就是对empty的判断
emptyview不为null 也就是我们设置了emptyview 而且此时没有数据,emptyview 会设置为可见,如果不为空且存在,就设置为gone.这就解释了为什么一开始要设置为gone的原因,emptyview的显示和隐藏是adapter来控制的。知道了这个我所遇到的问题就好解决了,因为设置了两次emptyview,但是每次adapter只会对最后一次设置的emptyview控制显示、隐藏,所以只需要每次在设置emptyview前,将所有emptyview设置为gone,然后设置emptyview,这样就会每次只显示我们所要显示的emptyview了。
看到stackoverflow 的 一个关于使用两种emptyview的答案
If I got error or got no data from database or server, I set visibility of ProgressBar to Gone and change visibility of TextView to Visible. And then set TextView as empty view of my ListView.
并不需要每次手动设置emptyview为Visible,adapterview会根据当前状态设置emptyview是显示还是隐藏,我们只需将他们都设置为gone即可.
如果遇到要使用多种emptyview的情况,可能使用第二种的方法会很好,但是只有一种emptyview而且项目中列表无数据提示的样式是一样的情况下,将设置emptyview的代码写成公共类就方便多了,或者每次动态添加前先将adapterview的parent中的其他view移除,然后再添加?这种还没试过。