ScrollView嵌套recyclerView出现的滑动问题

Posted oooohuhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ScrollView嵌套recyclerView出现的滑动问题相关的知识,希望对你有一定的参考价值。

记得以前在解决scrollView与ListView嵌套问题时,那个时候是自定义了listView去测量listView高度,今天项目中刚 好碰到了要用recycerView,同样也是嵌套在scrollView中,但是按照以前listView方法居然不显示了,后来发现原来是要重写的是 LayoutManager...

在此说明,这是copy大神的,我只是为了学习啊!大神真的很牛啊!

原创博客:http://blog.csdn.net/u010623588/article/details/50262367

重写的LinearLayoutManager

 1     public class FullyLinearLayoutManager extends LinearLayoutManager {  
 2       
 3         private static final String TAG = FullyLinearLayoutManager.class.getSimpleName();  
 4       
 5         public FullyLinearLayoutManager(Context context) {  
 6             super(context);  
 7         }  
 8       
 9         public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {  
10             super(context, orientation, reverseLayout);  
11         }  
12       
13         private int[] mMeasuredDimension = new int[2];  
14       
15         @Override  
16         public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,  
17                               int widthSpec, int heightSpec) {  
18       
19             final int widthMode = View.MeasureSpec.getMode(widthSpec);  
20             final int heightMode = View.MeasureSpec.getMode(heightSpec);  
21             final int widthSize = View.MeasureSpec.getSize(widthSpec);  
22             final int heightSize = View.MeasureSpec.getSize(heightSpec);  
23       
24             Log.i(TAG, "onMeasure called. \nwidthMode " + widthMode  
25                     + " \nheightMode " + heightSpec  
26                     + " \nwidthSize " + widthSize  
27                     + " \nheightSize " + heightSize  
28                     + " \ngetItemCount() " + getItemCount());  
29       
30             int width = 0;  
31             int height = 0;  
32             for (int i = 0; i < getItemCount(); i++) {  
33                 measureScrapChild(recycler, i,  
34                         View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
35                         View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
36                         mMeasuredDimension);  
37       
38                 if (getOrientation() == HORIZONTAL) {  
39                     width = width + mMeasuredDimension[0];  
40                     if (i == 0) {  
41                         height = mMeasuredDimension[1];  
42                     }  
43                 } else {  
44                     height = height + mMeasuredDimension[1];  
45                     if (i == 0) {  
46                         width = mMeasuredDimension[0];  
47                     }  
48                 }  
49             }  
50             switch (widthMode) {  
51                 case View.MeasureSpec.EXACTLY:  
52                     width = widthSize;  
53                 case View.MeasureSpec.AT_MOST:  
54                 case View.MeasureSpec.UNSPECIFIED:  
55             }  
56       
57             switch (heightMode) {  
58                 case View.MeasureSpec.EXACTLY:  
59                     height = heightSize;  
60                 case View.MeasureSpec.AT_MOST:  
61                 case View.MeasureSpec.UNSPECIFIED:  
62             }  
63       
64             setMeasuredDimension(width, height);  
65         }  
66       
67         private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,  
68                                        int heightSpec, int[] measuredDimension) {  
69             try {  
70                 View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException  
71       
72                 if (view != null) {  
73                     RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();  
74       
75                     int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,  
76                             getPaddingLeft() + getPaddingRight(), p.width);  
77       
78                     int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,  
79                             getPaddingTop() + getPaddingBottom(), p.height);  
80       
81                     view.measure(childWidthSpec, childHeightSpec);  
82                     measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;  
83                     measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;  
84                     recycler.recycleView(view);  
85                 }  
86             } catch (Exception e) {  
87                 e.printStackTrace();  
88             } finally {  
89             }  
90         }  
91     }  

 

以及重写的GridViewLayout:

  1     public class FullyGridLayoutManager extends GridLayoutManager {  
  2       
  3         private int mwidth = 0;  
  4         private int mheight = 0;  
  5       
  6         public FullyGridLayoutManager(Context context, int spanCount) {  
  7             super(context, spanCount);  
  8         }  
  9       
 10         public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {  
 11             super(context, spanCount, orientation, reverseLayout);  
 12         }  
 13       
 14         private int[] mMeasuredDimension = new int[2];  
 15       
 16         public int getMwidth() {  
 17             return mwidth;  
 18         }  
 19       
 20         public void setMwidth(int mwidth) {  
 21             this.mwidth = mwidth;  
 22         }  
 23       
 24         public int getMheight() {  
 25             return mheight;  
 26         }  
 27       
 28         public void setMheight(int mheight) {  
 29             this.mheight = mheight;  
 30         }  
 31       
 32         @Override  
 33         public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {  
 34             final int widthMode = View.MeasureSpec.getMode(widthSpec);  
 35             final int heightMode = View.MeasureSpec.getMode(heightSpec);  
 36             final int widthSize = View.MeasureSpec.getSize(widthSpec);  
 37             final int heightSize = View.MeasureSpec.getSize(heightSpec);  
 38       
 39             int width = 0;  
 40             int height = 0;  
 41             int count = getItemCount();  
 42             int span = getSpanCount();  
 43             for (int i = 0; i < count; i++) {  
 44                 measureScrapChild(recycler, i,  
 45                         View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
 46                         View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),  
 47                         mMeasuredDimension);  
 48       
 49                 if (getOrientation() == HORIZONTAL) {  
 50                     if (i % span == 0) {  
 51                         width = width + mMeasuredDimension[0];  
 52                     }  
 53                     if (i == 0) {  
 54                         height = mMeasuredDimension[1];  
 55                     }  
 56                 } else {  
 57                     if (i % span == 0) {  
 58                         height = height + mMeasuredDimension[1];  
 59                     }  
 60                     if (i == 0) {  
 61                         width = mMeasuredDimension[0];  
 62                     }  
 63                 }  
 64             }  
 65       
 66             switch (widthMode) {  
 67                 case View.MeasureSpec.EXACTLY:  
 68                     width = widthSize;  
 69                 case View.MeasureSpec.AT_MOST:  
 70                 case View.MeasureSpec.UNSPECIFIED:  
 71             }  
 72       
 73             switch (heightMode) {  
 74                 case View.MeasureSpec.EXACTLY:  
 75                     height = heightSize;  
 76                 case View.MeasureSpec.AT_MOST:  
 77                 case View.MeasureSpec.UNSPECIFIED:  
 78             }  
 79             setMheight(height);  
 80             setMwidth(width);  
 81             setMeasuredDimension(width, height);  
 82         }  
 83       
 84         private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,  
 85                                        int heightSpec, int[] measuredDimension) {  
 86             if (position < getItemCount()) {  
 87                 try {  
 88                     View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException  
 89                     if (view != null) {  
 90                         RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();  
 91                         int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,  
 92                                 getPaddingLeft() + getPaddingRight(), p.width);  
 93                         int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,  
 94                                 getPaddingTop() + getPaddingBottom(), p.height);  
 95                         view.measure(childWidthSpec, childHeightSpec);  
 96                         measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;  
 97                         measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;  
 98                         recycler.recycleView(view);  
 99                     }  
100                 } catch (Exception e) {  
101                     e.printStackTrace();  
102                 }  
103             }  
104         }  
105     }  

 还有一个瀑布流StaggeredGridLayoutManager和ScrollView进行嵌套

  1 StaggeredGridLayoutManager和ScrollView进行嵌套  3 
  4 package com.kale.waterfalldemo.extra.RecyclerView;
  5 
  6 import android.support.v7.widget.RecyclerView;
  7 import android.support.v7.widget.StaggeredGridLayoutManager;
  8 import android.view.View;
  9 import android.view.ViewGroup;
 10 
 11 /**
 12  * @author Jack Tony
 13  * @brief 不规则排列(类似于瀑布流)的布局管理器
 14  * @date 2015/4/6
 15  */
 16 public class ExStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
 17 
 18     public ExStaggeredGridLayoutManager(int spanCount, int orientation) {
 19         super(spanCount, orientation);
 20     }
 21 
 22     // 尺寸的数组,[0]是宽,[1]是高
 23     private int[] measuredDimension = new int[2];
 24 
 25     // 用来比较同行/列那个item罪宽/高
 26     private int[] dimension;
 27 
 28 
 29     @Override
 30 
 31     public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
 32         // 宽的mode+size
 33         final int widthMode = View.MeasureSpec.getMode(widthSpec);
 34         final int widthSize = View.MeasureSpec.getSize(widthSpec);
 35         // 高的mode + size
 36         final int heightMode = View.MeasureSpec.getMode(heightSpec);
 37         final int heightSize = View.MeasureSpec.getSize(heightSpec);
 38 
 39         // 自身宽高的初始值
 40         int width = 0;
 41         int height = 0;
 42         // item的数目
 43         int count = getItemCount();
 44         // item的列数
 45         int span = getSpanCount();
 46         // 根据行数或列数来创建数组
 47         dimension = new int[span];
 48 
 49         for (int i = 0; i < count; i++) {
 50             measureScrapChild(recycler, i,
 51                     View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
 52                     View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredDimension);
 53 
 54            // 如果是竖直的列表,计算item的高,否则计算宽度
 55             //Log.d("LISTENER", "position " + i + " height = " + measuredDimension[1]);
 56             if (getOrientation() == VERTICAL) {
 57                 dimension[findMinIndex(dimension)] += measuredDimension[1];
 58             } else {
 59                 dimension[findMinIndex(dimension)] += measuredDimension[0];
 60             }
 61         }
 62         if (getOrientation() == VERTICAL) {
 63             height = findMax(dimension);
 64         } else {
 65             width = findMax(dimension);
 66         }
 67         
 68 
 69         switch (widthMode) {
 70             // 当控件宽是match_parent时,宽度就是父控件的宽度
 71             case View.MeasureSpec.EXACTLY:
 72                 width = widthSize;
 73                 break;
 74             case View.MeasureSpec.AT_MOST:
 75                 break;
 76             case View.MeasureSpec.UNSPECIFIED:
 77                 break;
 78         }
 79         switch (heightMode) {
 80             // 当控件高是match_parent时,高度就是父控件的高度
 81             case View.MeasureSpec.EXACTLY:
 82                 height = heightSize;
 83                 break;
 84             case View.MeasureSpec.AT_MOST:
 85                 break;
 86             case View.MeasureSpec.UNSPECIFIED:
 87                 break;
 88         }
 89         // 设置测量尺寸  
 90         setMeasuredDimension(width, height);
 91     }
 92 
 93     private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
 94             int heightSpec, int[] measuredDimension) {
 95 
 96         // 挨个遍历所有item
 97         if (position < getItemCount()) {
 98             try {
 99                 View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException
100 
101                 if (view != null) {
102                     RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
103                     int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), lp.width);
104                     int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), lp.height);
105                     // 子view进行测量,然后可以通过getMeasuredWidth()获得测量的宽,高类似
106                     view.measure(childWidthSpec, childHeightSpec);
107                     // 将item的宽高放入数组中
108                     measuredDimension[0] = view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
109                     measuredDimension[1] = view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
110                     recycler.recycleView(view);
111                 }
112             } catch (Exception e) {
113                 e.printStackTrace();
114             }
115         }
116     }
117 
118     private int findMax(int[] array) {
119         int max = array[0];
120         for (int value : array) {
121             if (value > max) {
122                 max = value;
123             }
124         }
125         return max;
126     }
127 
128     /**
129      * 得到最数组中最小元素的下标
130      *
131      * @param array
132      * @return
133      */
134     private int findMinIndex(int[] array) {
135         int index = 0;
136         int min = array[0];
137         for (int i = 0; i < array.length; i++) {
138             if (array[i] < min) {
139                 min = array[i];
140                 index = i;
141             }
142         }
143         return index;
144     }
145    
146 }

 

重写完之后,用就好说了,在adapter的onBindview和平常一样用就可以了

1     final FullyGridLayoutManager manager = new FullyGridLayoutManager(context.getActivity(), 3);  
2            manager.setOrientation(GridLayoutManager.VERTICAL);  
3            manager.setSmoothScrollbarEnabled(true);  
4            viewHolder.recyclerView.setLayoutManager(manager);  

 


 

关键是,还有个坑爹的问题:

此种方法在4.x系统上好用,能显示滑动也流畅,但是在5.x上虽然显示正常,但是滑动的时候好像被粘住了,没有惯性效果。。。。
最后解决方法是重写最外层的Scrollview

 1     **  
 2      * 屏蔽 滑动事件  
 3      */  
 4     public class MyScrollview extends ScrollView {  
 5         private int downX;  
 6         private int downY;  
 7         private int mTouchSlop;  
 8       
 9         public MyScrollview(Context context) {  
10             super(context);  
11             mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
12         }  
13       
14         public MyScrollview(Context context, AttributeSet attrs) {  
15             super(context, attrs);  
16             mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
17         }  
18       
19         public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {  
20             super(context, attrs, defStyleAttr);  
21             mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  
22         }  
23       
24         @Override  
25         public boolean onInterceptTouchEvent(MotionEvent e) {  
26             int action = e.getAction();  
27             switch (action) {  
28                 case MotionEvent.ACTION_DOWN:  
29                     downX = (int) e.getRawX();  
30                     downY = (int) e.getRawY();  
31                     break;  
32                 case MotionEvent.ACTION_MOVE:  
33                     int moveY = (int) e.getRawY();  
34                     if (Math.abs(moveY - downY) > mTouchSlop) {  
35                         return true;  
36                     }  
37             }  
38             return super.onInterceptTouchEvent(e);  
39         }  
40     }  

 

这样就可以了,暴力屏蔽。。。。5以上的事件直接传递给了内层的recyclerview,所以我们把滑动事件拦截就好了。。。

以上是关于ScrollView嵌套recyclerView出现的滑动问题的主要内容,如果未能解决你的问题,请参考以下文章

scrollview嵌套上下拉控件嵌套recyclerview

嵌套的scrollview + recyclerview,奇怪的自动滚动行为[重复]

Android Scrollview嵌套RecyclerView导致滑动卡顿问题解决

解决ScrollView嵌套RecyclerView的显示及滑动问题

ScrollView嵌套recyclerView出现的滑动问题

scrollview嵌套recyclerview卡顿现象