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,所以我们把滑动事件拦截就好了。。。

时间: 2025-01-11 17:32:18

ScrollView嵌套recyclerView出现的滑动问题的相关文章

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

一个比较长的界面一般都是Scrollview嵌套RecyclerView来解决.不过这样的UI并不是我们开发人员想看到的,实际上嵌套之后.因为Scrollview和RecyclerView都是滑动控件.会有一点滑动上的冲突.导致滑动起来有些卡顿.这个时候.我们重写一下LayoutManager就行了 例如: [java] view plain copy LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getAct

(转载) Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题 标签: scrollviewandroid滑动嵌套 2015-07-16 17:24 11126人阅读 评论(17) 收藏 举报  分类: Android进阶(19)  版权声明:本文为博主原创文章,未经博主允许不得转载. scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview的高度,比如: ViewGroup.L

Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题

scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview的高度,比如: ViewGroup.LayoutParams mParams = recyclerView.getLayoutParams(); mParams.height = (CommonUtils.getScreenWidthPX(getActivity()) * 480 / 720 + CommonUtils.dipToPixels(40)) * num

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

项目中时常需要实现在ScrollView中嵌入一个或多个RecyclerView.这一做法通常会导致如下几个问题 页面滑动卡顿 ScrollView高度显示不正常 RecyclerView内容显示不全 本文将利用多种方式分别解决上述问题 滑动卡顿解决方案 若只存在滑动卡顿这一问题,可以采用如下两种简单方式快速解决 利用RecyclerView内部方法 recyclerView.setHasFixedSize(true); recyclerView.setNestedScrollingEnable

Android 解决ScrollView嵌套RecyclerView导致滑动不流畅的问题

最近做的项目中遇到了ScrollView嵌套RecyclerView,刚写完功能测试,直接卡出翔了,后来通过网上查找资料和 自己的实践,找出了两种方法解决这个问题. 首先来个最简单的方法: recyclerView.setNestedScrollingEnabled(false); 这个方法就可以解决这一问题. 既然有首先那肯定有第二种解决的办法,只不过相对于第一种方法来说就太麻烦了. 我们知道ScrollView嵌套listView或者GridView的时候需要自定义listView或者是Gr

ScrollView嵌套EditText联带滑动的解决办法

解决ScrollView嵌套EditText的滑动事件,并且实现它们两者之间的联带滑动.什么是联带滑动呢,就是当EditText滑动到底部的时候,这时就应该让外部的ScrollView跟着滑动,好让它们之间完成连贯的滑动事件.先来看看效果把. 网上没找到完整实现的例子,只好自己撸demo了.代码里有注释,全部代码如下: package chn.fz.thatjay.scrolleditview.view; import android.content.Context; import androi

解决ScrollView嵌套ViewPager出现的滑动冲突问题

/** * */ public class ScrollView1 extends ScrollView { private boolean canScroll; private GestureDetector mGestureDetector; View.OnTouchListener mGestureListener; public ScrollView1(Context context, AttributeSet attrs) { super(context, attrs); mGestu

scrollview嵌套上下拉控件嵌套recyclerview

相信会碰到很多类似的需求,一个列表控件,然后控件上方的一个头部需要自定义,这样就不好有时候也不能加在列表控件的头部了,那必须得嵌套一层scrollview了,没毛病,那么一般的列表控件都是有上拉下拉的操作,而且一般也是在 github 上找寻一个收藏量高的 来做为一个全局通用的上下拉控件,这里问题就来了,一般的 scrollview 嵌套 recyclerview 或者 listview 都毕竟容易解决,可是在加上一层上下拉控件呢?上下拉控件肯定会有它自己的触摸处理机制,这样你改起来也很麻烦,这

从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法

本篇文章假设读者没有任何的触摸事件基础知识,所以我们会从最基本的触摸事件分发处说起. ScrollView为什么会出现嵌套EditText出现滑动事件冲突呢?相信你会有这种疑问,我们来看这么一种情况: 有一个固定高度的EditText,假设它只能显示3行文本,但是,我们在其中输入的文本多余三行时,那么这时就需要可以在EditText内部进行小幅滚动了.那么将这个EditText放入了ScrollView当中, 并且ScrollView内容过多以致ScrollView也可以滑动,这时候就会出现Ed