OK ,最近做了一个项目 是管理类的软件 里面到处用的都是PullToRefreshListView 这个控件, 今天就要讲讲这个奇葩的坑,感谢网上 有些大佬已经踩过坑总结的一些,但是我发现资料不多,讲的都是一类问题,或者没有从本质上追溯一下。
我在来总结一下,方便他人,也方便自己。有2种原因:
原因1、PullToRefreshListView 使用的时候: 一定要设置成:
android:layout_width="match_parent"
android:layout_height="match_parent" 不然真的显示不了(什么原因,那只能从源码来看了)
首先看看我在xml里面是怎么写的:
<com.handmark.pulltorefresh.library.PullToRefreshListView
android:id="@+id/listview1"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:divider="#f2f2f4"
android:dividerHeight="1dp"
android:scrollbars="none"
/>
网上总结的最多就是这个问题了,设置成match_parent,但是我明明设置成了啊,真的,我检查很多遍了。但是就是不显示,后来我测量了一下listView 的宽高:
一直是这样的:
在onCreate中 测量下:
01-18 10:15:58.293 7085-7085/com.eris.ict4 E/superMan: height: 0------- width 680
发现宽是680,高是0, 宽是有的,因为我设置的是match_parent,那为什么高没有呢,真是奇怪,你肯定会说,在onCreate里啊,它的 adapter里面没有数据啊,就是默认的高度啊,恩,是这么个道理。
我们看看在数据请求回调成功后的测量,时间是01-18 10:16:01.389 7085-7085,也请求成功了,也有数据了,也走Adapterde 的getView()方法了,就是不显示。 我内个去了,
01-18 10:16:01.389 7085-7085/com.eris.ict4 E/superMan: height: 0------- width 680
测量后发现还是不显示,高度还是为0;
解决方法1:
好了 ,不 卖关子了,最后在网上找的一个 哥们说在onCreate 中 先设置 listView.setVisibility(View.GONE);
最后在请求数据成功的回调里 在设置 listView.setVisibility(View.VISIBLE); 说就可以, 我试了试,是可以了,但是可惜的是他没有说明为什么这样可以,
其实,你在onCreate 中 先设置 listView.setVisibility(View.INVISIBLE),然后在回调里设置listView.setVisibility(View.VISIBLE); 结果还是不显示,测量后的高度还是0;
01-18 10:18:30.363 7371-7371/com.eris.ict4 E/superMan: height: 0------- width 680
那我们就要说说 :View三种属性:VISIBLE,INVISIBLE,GONE 的区别,
其实网上总结也很多:
VISIBLE 已经在屏幕上绘制出来并且可见;
INVISIBLE 已经绘制出来不可见 保留它的位置,不重新layout
Gone 不可见并且没有绘制出来
所以说gone还是比较消耗性能的,如果你要显示的话,它重新 测量 布局 绘制
解决方法2 :
第二个方法是我比较推崇的,虽然说第一种方法有点像奇淫技巧,也很省事, 但是第二种就是能学习一下他的源码
我们发现它总是无法准确测量到自己高度 那我们可以自己手动给他设置一个高度, 那我们怎么去设置呢,怎么给它设置呢?
我们去它的源码看看:
public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView>
好我们接着去PullToRefreshAdapterViewBase看看
public abstract class PullToRefreshAdapterViewBase<T extends AbsListView> extends PullToRefreshBase<T> implements OnScrollListener
我们在 到PullToRefreshBase 里面看看:
public abstract class PullToRefreshBase<T extends View> extends LinearLayout implements IPullToRefresh<T>
我们发现PullToRefreshBase 是继承LinearLayout ,其实无论是么样的控件 最后都是 view 或者 viewGroup 好 扯远了,
我们回归正题:
我们来看它内部的代码:
@Override
protected final void onSizeChanged(int w, int h, int oldw, int oldh) {
if (DEBUG) {
Log.d(LOG_TAG, String.format("onSizeChanged. W: %d, H: %d", w, h));
}
super.onSizeChanged(w, h, oldw, oldh);
// We need to update the header/footer when our size changes
refreshLoadingViewsSize();
// Update the Refreshable View layout
refreshRefreshableViewSize(w, h);
/**
* As we're currently in a Layout Pass, we need to schedule another one
* to layout any changes we've made here
*/
post(new Runnable() {
@Override
public void run() {
requestLayout();
}
});
}
原来 它就是在这里设置宽高的:
protected final void refreshRefreshableViewSize(int width, int height) {
// We need to set the Height of the Refreshable View to the same as
// this layout
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mRefreshableViewWrapper.getLayoutParams();
switch (getPullToRefreshScrollDirection()) {
case HORIZONTAL:
if (lp.width != width) {
lp.width = width;
mRefreshableViewWrapper.requestLayout();
}
break;
case VERTICAL:
if (lp.height != height) {
lp.height = height;
mRefreshableViewWrapper.requestLayout();
}
break;
}
}
那我们拿到这个mRefreshableViewWrapper 就可以设置 它的宽高了 是不是?
怎么拿到呢?
protected FrameLayout getRefreshableViewWrapper() {
return mRefreshableViewWrapper;
}
改成公共的
我们来试试看:这里的200我是写死的,只是测试一下,正常的应该算下 应该拿屏幕的高度,减去已经使用的高度,剩下就是这listView 能用的高度
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) listView.getRefreshableViewWrapper().getLayoutParams();
layoutParams.height=Constants.dip2px(mActivity,200);
listView.getRefreshableViewWrapper().setLayoutParams(layoutParams);
正常显示了!
方法1 和方法2 都是可以的!
转载请说明出处,谢谢!