首页 > 代码库 > ScrollView ViewPager ListView三者共存的问题
ScrollView ViewPager ListView三者共存的问题
场景描述:
ScrollView是整个界面的外层滑动控件,嵌套在里面的布局是ViewPager,ViewPager里面其中一个Page是ListView控件。
问题描述:
ViewPager中的ListView获取到数据后不能显示,也就是不能展开,外层ScrollView不能滑动.
解决思路:
1、让ListView展开。(网上的说法是ScrollView与ListView嵌套不可取,但开发中设计界面如此,不用也不成,闲话少说),想让ListView撑开,只能依靠设置Adapter每个Item高度,然后计算所有Item占用的总高度,从而得到ListView的高度,重新设置ListView的高度(工具类都是网上的,我又多说话了还是粘在下面)。
package com.goodwin.finance.util; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import android.widget.ListView; /** * 文件名: com.goodwin.finance.util.ViewUtil * 作者: 熊杰 Wilson * 日期: 14-9-30 * 时间: 14:28 * 开发工具: IntelliJ IDEA 12.1.1 * 开发语言: Java,Android * 开发框架: * 版本: v0.1 * <strong>软件中所有与布局相关的工具类</strong> * <p></p> */ public class ViewUtil { public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } /** * 获取Listview的高度,然后设置ViewPager的高度 * @param listView * @return */ public static int setListViewHeightBasedOnChildren1(ListView listView) { //获取ListView对应的Adapter ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return 0; } int totalHeight = 0; for (int i = 0, len = listAdapter.getCount(); i < len; i++) { //listAdapter.getCount()返回数据项的数目 View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); //计算子项View 的宽高 totalHeight += listItem.getMeasuredHeight(); //统计所有子项的总高度 } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); //listView.getDividerHeight()获取子项间分隔符占用的高度 //params.height最后得到整个ListView完整显示需要的高度 listView.setLayoutParams(params); return params.height; } }
用法是在获取到数据填充ListView适配器后,调用工具类的方法。
infoListAdapter = new TheInfoListAdapter(this); infoListAdapter.setInfoList(infoList); lvInfoList.setAdapter(infoListAdapter); infoListAdapter.notifyDataSetChanged(); int listViewHeight = ViewUtil.setListViewHeightBasedOnChildren1(lvInfoList); ViewGroup.LayoutParams params = vpImgpager.getLayoutParams(); params.height = listViewHeight; vpZifuduo.setLayoutParams(params);
2、为什么调用的是工具类的第2个方法,是因为第一个方法调用之后,它只影响到ListView的高度,并不影响它外层ViewPager的高度,因此我重载了这个方法,将这个高度给返回,在改变ListView高度的同时,也将ViewPager的高度重新动态设置。这样也就解决了外层ScrollView不能滑动的问题。
注意下细节:
ListView的适配器Item用LinearLayout进行布局,给它指定一个固定高度(这个高度值固定对兼容来说无伤大雅),这样便于计算ListView的高度。
3、附带的另外一个问题,ViewPager的左右滑动与ScrollView的上下滑动问冲突
解决方法是自定义一个ScrollView,然后重写一个onInterceptTouchEvent()方法
以下是我本例中重写的ScrollView:
package com.goodwin.finance.common.view; import android.content.Context; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ScrollView; public class MyScrollView extends ScrollView { private float xDistance, yDistance, xLast, yLast; private OnScrollListener onScrollListener; /** * 主要是用在用户手指离开MyScrollView,MyScrollView还在继续滑动,我们用来保存Y的距离,然后做比较 */ private int lastScrollY; public MyScrollView(Context context) { this(context, null); } public MyScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 设置滚动接口 * @param onScrollListener */ public void setOnScrollListener(OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } /** * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中 */ private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { int scrollY = MyScrollView.this.getScrollY(); //此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息 if(lastScrollY != scrollY){ lastScrollY = scrollY; handler.sendMessageDelayed(handler.obtainMessage(), 5); } if(onScrollListener != null){ onScrollListener.onScroll(scrollY); } }; }; /** * 重写onTouchEvent, 当用户的手在MyScrollView上面的时候, * 直接将MyScrollView滑动的Y方向距离回调给onScroll方法中,当用户抬起手的时候, * MyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理 * MyScrollView滑动的距离 */ @Override public boolean onTouchEvent(MotionEvent ev) { if(onScrollListener != null){ onScrollListener.onScroll(lastScrollY = this.getScrollY()); } switch(ev.getAction()){ case MotionEvent.ACTION_UP: handler.sendMessageDelayed(handler.obtainMessage(), 5); break; } return super.onTouchEvent(ev); } /** * * 滚动的回调接口 * */ public interface OnScrollListener{ /** * 回调方法, 返回MyScrollView滑动的Y方向距离 */ public void onScroll(int scrollY); } /** *解决ViewPager与ScrollView手势冲突的问题 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: xDistance = yDistance = 0f; xLast = ev.getX(); yLast = ev.getY(); break; case MotionEvent.ACTION_MOVE: final float curX = ev.getX(); final float curY = ev.getY(); xDistance += Math.abs(curX - xLast); yDistance += Math.abs(curY - yLast); xLast = curX; yLast = curY; if(xDistance > yDistance){ return false; } } return super.onInterceptTouchEvent(ev); } }
ScrollView ViewPager ListView三者共存的问题