ScrollView与listView,GridView,Vie

作者: 你需要一台永动机 | 来源:发表于2016-05-31 01:11 被阅读1176次

    ScrollView是带有滚动事件的控件,与listView和GridView以及Viewpager嵌套使用时经常会出现很多问题。例如listView和GridView只能在ScrollView显示一行等。所以Google是不推荐我们去做ScrollView内嵌操作的,但是有的时候,需求需要~我们不得不这么使用。所以接下来我给大家讲一些基础的解决冲突的办法。

    1.ScrollView嵌套ListView,有2种方法解决

    1.1自定义View
    public class ScrollListView extends ListView {
        public ScrollListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }
    
        public ScrollListView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                    MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    }
    
    1.2动态测量Listview的高度
    /**
     * 动态控制listView的高度
     */
    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);
    }
    

    2.ScrollView嵌套GridView,有2种方法解决---与ListView类似

    2.1自定义View
    public class ScrollGridView extends GridView {
        public ScrollGridView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }
    
        public ScrollGridView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                    MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, expandSpec);
        }
    }
    
    2.2动态测量Gridview的高度
    /**
     * 动态控制gridview的高度
     */
    public static void setGridViewHeightBasedOnChildren(GridView gridView, int number) {
        //获取listview的适配器
        ListAdapter listAdapter = gridView.getAdapter();
        int numCollumn = number;
        //item的高度
        if (listAdapter == null) {
            return;
        }
        int totalHeight = 0;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            if (i % numCollumn == 0) {
                View listItem = listAdapter.getView(i, null, gridView);
                listItem.measure(0, 0);
                totalHeight += listItem.getMeasuredHeight();
            }
        }
        ViewGroup.LayoutParams params = gridView.getLayoutParams();
        params.height = totalHeight;
        gridView.setLayoutParams(params);
    }
    

    3.ScrollView嵌套ViewPager,有2种方法解决

    3.1自定义ScrollView
    /** 
      * 能够兼容ViewPager的ScrollView 
      *  
      * @Description: 解决了ViewPager在ScrollView中的滑动反弹问题 
      */  
    public class ScrollViewExtend extends ScrollView {  
        // 滑动距离及坐标  
        private float xDistance, yDistance, xLast, yLast;  
      
        public ScrollViewExtend(Context context, AttributeSet attrs) {  
            super(context, attrs);  
        }  
      
        @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);  
        }  
    }  
    
    3.2自定义viewPager
    public class MyViewPager extends ViewPager {
        /**
         * 触摸时按下的点
         **/
        PointF downP = new PointF();
        /**
         * 触摸时当前的点
         **/
        PointF curP = new PointF();
        OnSingleTouchListener onSingleTouchListener;
    
        public MyViewPager(Context context) {
            super(context);
        }
    
        public MyViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        @Override
        public boolean onTouchEvent(MotionEvent arg0) {
            // 每次进行onTouch事件都记录当前的按下的坐标
            curP.x = arg0.getX();
            curP.y = arg0.getY();
    
            if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
                // 记录按下时候的坐标
                // 切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变
                downP.x = arg0.getX();
                downP.y = arg0.getY();
                // 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
                getParent().requestDisallowInterceptTouchEvent(true);
            }
    
            if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
                // 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
                getParent().requestDisallowInterceptTouchEvent(true);
            }
    
            if (arg0.getAction() == MotionEvent.ACTION_UP) {
                // 在up时判断是否按下和松手的坐标为一个点
                // 如果是一个点,将执行点击事件,这是我自己写的点击事件,而不是onclick
                if (downP.x == curP.x && downP.y == curP.y) {
                    onSingleTouch();
                    return true;
                }
            }
    
            return super.onTouchEvent(arg0);
        }
        /**
         * 单击
         */
        public void onSingleTouch() {
            if (onSingleTouchListener != null) {
    
                onSingleTouchListener.onSingleTouch();
            }
        }
    
        /**
         * 创建点击事件接口
         */
        public interface OnSingleTouchListener {
            public void onSingleTouch();
        }
    
        public void setOnSingleTouchListener(
                OnSingleTouchListener onSingleTouchListener) {
            this.onSingleTouchListener = onSingleTouchListener;
        }
    }
    

    4.若嵌套的ListView和GridView的高度超出了ScrollView,那么ScrollView会自动滑到底部。

    那么我们只需要使用一个顶部控件主动获取焦点便能解决这个问题。解决代码如下。

        view.setFocusable(true);  
        view.setFocusableInTouchMode(true);  
        view.requestFocus();  
    

    备注:自定义ListView的详细介绍 传送门

    相关文章

      网友评论

      • 你需要一台永动机:重复加载布局是具体指?可以交流下~
      • 八怪不姓丑:2.1方法虽然可以解决只显示一行的冲突,但是在Fragment中,会重复加载布局的问题怎么解决?
      • IAM四十二:自定义listview 会导致view复用的机制失效,所以这种需求的确很坑
      • hfk:刚好用到,mark
      • c2d4631a3227:MyViewPager里的只有getParent().requestDisallowInterceptTouchEvent(true); 这句失去意义了。不然会有getParent().requestDisallowInterceptTouchEvent(false)。
        你需要一台永动机:@大黑黑 懂了,感谢~
      • 你需要一台永动机:如果有不对的地方,请大伙帮忙指明一下,感谢了~~

      本文标题:ScrollView与listView,GridView,Vie

      本文链接:https://www.haomeiwen.com/subject/xiecdttx.html