您的位置:首页 > 移动开发 > Android开发

关于Android中ScrollView嵌套ListView的问题

2015-05-31 21:12 423 查看
最近有用到ScrollView嵌套ListView,出现的问题相信大家都知道,就是ListView只显示一点,并且无法滑动,下面我就写上我的解决方案,供大家参考。

具体方法就是自定义ListView,下面是代码

public class MyListView extends ListView {

private Activity activity;
private DisplayMetrics dm;

public Activity getActivity() {
return activity;
}

public void setActivity(Activity activity) {
this.activity = activity;
}

public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
dm = new DisplayMetrics();
}

public MyListView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}

public MyListView(Context context) {
this(context,null);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenHeight = dm.heightPixels;

int expandSpec = MeasureSpec.makeMeasureSpec(screenHeight/3,
MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, expandSpec);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
//System.out.println("ListView onTouchEvent");
//System.out.println(this.getHeight());
getParent().requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(ev);
}

}
最关键是部分是重写了回调函数onMeasure,我呢在这个函数中,获取了屏幕的高度,并且重新定义了一个heightMeasureSpec,而不是用父组件传递过来的heightMeasureSpec,最后调用super.onMeasure(widthMeasureSpec, expandSpec);将自己拼装的heightMeasureSpec传递出去,这样就可以了,实现了自定义ListView的高度,具体onMeasure的使用大家可以参考郭大侠的博客 http://blog.csdn.net/guolin_blog/article/details/16330267。
相信大家在网上都看到过类似的代码,但是在int expandSpec = MeasureSpec.makeMeasureSpec(screenHeight/3,MeasureSpec.AT_MOST); 这句话里设定的高度值都是Integer.Max,这样的话会让所有的ListView都显示出来(但是大家千万不要以后Integer.Max就是这样用的,不信你去自定义一个View在onMeasure中这样写,你就会发现错误了,自定义ListView可以这样的原因是父类的onMeasure中会处理这样面的逻辑),但是我我觉得让所有的ListView都显示出来不太好,这样还需要ListView干嘛呢?其实最简单的方法是直接在makeMeasureSpec中设定一个固定值,比如400,但是这样又不利于适配,所以我取的是屏幕的三分之一。

这里大家可能又要奇怪了,为什么获取个屏幕高度要这么麻烦呢?直接在自定义的ListView里定义一个变量并加上setter和getter,然后在Activity中获取并设置,这样不是更方面吗?如果你这么做了,你会发现这样取出来的值是0!这是为什么呢?原因就是你在Activity的onCreate()中是不能直接获取到任何和组件相关的宽高的,具体的原因设计到Android的UI message,简单的说就是android绘制组件要在onResume()中才会进行,所以直接在onCreate()中获取的就是0,解决方案也有两个,第一个就是在onCreate()中使用listview.post()方案,在新建的runnable中获取宽高,post方法会将runnable封装成一个message并且丢到消息队列中,并不会马上执行,要等Looper循环到这个message才会handle
it,但是这又有一个问题了,onMeasure会比你的自定义的ListView的setter更早的执行,你要在哪里取出高度呢?不太好办吧,所以我这里采取的第二种方法,直接把activity实例传过来,在onMeasure中获取高度。

最后一个问题,就是你会发现,我重写了ListView的onTouchEvent并且设置了getParent().requestDisallowInterceptTouchEvent(true);,这个函数的作用是告诉父组件,不要拦截我的事件,让我自己处理,因为你如果不设置,你会发现ListView滑动不了,相对应的滑动的是ScrollView。但是,如果你像网上大多数的那样让ListView全部显示出来,你会发现,相反的,重写了onTouchEvent竟然滑动不了,什么都不做竟然是最好的!这是为什么呢?原因也很简单,就是其实你滑动的就是ScrollView,只不过你的ListView全部显示出来了,滑动ScrollView就相当于滑动ListView,如果你拦截的touch事件,那事件就会给ListView自己处理,但是ListView已经全部显示了啊(这里所说的全部显示,不是针对于屏幕来说的,而是针对于父组件来说的,一定要注意)!怎么可能滑动呢,你说对不对?

好了,这就是全部内容了。有不足之处希望大家不吝赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: