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);
    }

}

时间: 2024-12-22 06:57:11

ScrollView ViewPager ListView三者共存的问题的相关文章

ScrollView viewPager ListView 结合使用的问题及解决办法

1. 解决ScrollView 和viewPager滑动冲突的问题 需要重写ScrollView ,使得viewpager获取到横向滑动事件 代码如下 public class PagerScrollView extends ScrollView { private GestureDetector mGestureDetector; public PagerScrollView(Context context, AttributeSet attrs, int defStyle) { super(

android(9) ListView + ScrollView + ViewPager布局

一.ListView + ScrollView + ViewPager界面实现: 看了别人的源码总要总结一下,ListView与ScrollView两者之间是有冲突的,但有的时候,又不得不两者一块使用.主要就是ListView中item高度不确定,只要写死或先算出所有的item的高度和就能显示出你所需要的效果了. 效果图: 主界面: public class MainActivity extends Activity { // viewPager private MyPageAdapter vi

9.解决ScrollView与ListView共存时ListView高度无法完全显示的问题。

问题: ScrollView与ListView共存时,ListView会只显示一行,其它行无法显示. 解决方案: 重写ListView如下即可解决问题. /**解决ScorllView与ListView共存时,ListView只显示一行.不能完全显示的问题. * @author Caiyuan Huang * 2014-9-26 */ public class CustomListView extends ListView { public CustomListView(Context cont

Android仿小米商城商品详情界面UI,ScrollView嵌套ScrollView/WebView/ListView

最近公司没事,研究了下多嵌套滚动组件的事件分发,虽然以前也接触过,但都是拿网上的用,也是特别简单的,正好朋友也需要,就研究了下 这个Demo也不是很完善,放上来也是让各位大牛给指点一下,优化优化 使用情景: 小米商城商品详情界面,界面看似ScrollView,但当正常滚动到底部时,提示继续上拉显示更多详情,上拉后直接滚动到第二屏,第二屏是个ViewPager,ViewPager里面的各个pager有的是WebView有的是ListView,有的是ScrollView,一开始想想就特别头晕,后来理

Android高级控件——GridView ScrollView ViewPager (上)

Android高级控件--GridView ScrollView ViewPager (上) GridView 网格视图,网格视图组件,九宫图显示数据表格(一种控件) ScrollView滚动视图 是一个单一容器,只能包含一个组件. ViewPager左右滑动 SlideMenu侧边栏 PullToRefreshListView下拉刷新 ListView新闻 原声列表视图 <?xml version="1.0" encoding="utf-8"?> &l

ScrollView嵌套ListView、GridView只显示一行,psts显示不出来

我们经常会用到在ScrollView嵌套ListView.GridView,给layout_height设置wrap或者match的时候,结果只显示一行,而给它设置一个固定的高度虽然能显示出来,但是会显示不全,或者空出一段. 原因:ScrollView在计算高度的时候,如果是wrap或者是match就会出错,结果只显示一行. 解决方案:定义一个类GridView4ScrollView继承GridView,然后重写onMeasure方法 @Override /** * 重写该方法,重新计算Grid

一句话让你的ScrollView、ListView弹力十足

android默认的ScrollView.ListView在最顶端下拉或者最底端上拉的时候,都不会带有反弹效果,很生硬的让你不能继续拖动,不像iOS那样可以回弹,个人认为,iOS的交互还是略好一点,那么我们也来在Android下实现下这个功能,先看下效果图: 那么我们今天的目标是一句话实现,如何去做呢 我们还是先看下代码: package com.xys.flexible; import android.content.Context; import android.util.Attribute

anroid中ScrollView嵌套ListView

有时候项目里面需要ScrollView嵌套ListView,但是正常下ListView只会显示一行多一点,解决方法就是填充ListView数据后重新计算ListView的高度,这里有两种方法来实现. 第一种方法:重写ListView [java] view plaincopyprint? package com.jwzhangjie.test; import android.content.Context; import android.util.AttributeSet; import and

四种方案解决ScrollView嵌套ListView问题(转)

在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结构的原因.这个结构碰到的问题.几种解决方案和优缺点比较,这4个方面来为大家阐述.分析.总结. 实际上不光是ListView,其他继承自AbsListView的类也适用,包括ExpandableListView.GridView等等,为了方便说明,以下均用ListView来代表. 一. 为什么要使用S