ScrollView嵌套Viewpager嵌套瀑布流Recyclerview
来源:互联网 发布:windows有多少行代码 编辑:程序博客网 时间:2024/06/01 07:20
最近在工作中遇到这样一个情景,ScrollView嵌套Viewpager嵌套瀑布流Recyclerview,让我踩到一个大坑,首先是scrollview和viewpager的嵌套问题继而又遇到viewpager嵌套瀑布流recyclerview的问题,让我绞尽脑汁。
最后想出一个办法:
1.首先重写Scrollview解决滑动冲突问题。
2.因为viewpager被嵌套在scrollview中会遇到不能显示完全的问题,所以重写viewpager,让viewpager每次自己去测量高度。
3.viewpager如何去自己测量高度,而且其中还包含的recyclerview,这就很麻烦了所以我们要重写recyclerview的layoutmanager。
public class CustomScrollView extends ScrollView { private float preX; private float preY; private float touchSlop; private boolean isViewPagerDragged; public CustomScrollView(Context context) { this(context, null); } public CustomScrollView(Context context, AttributeSet attrs) { super(context, attrs); touchSlop= ViewConfiguration.get(context).getScaledTouchSlop(); } /** * 在onInterceptTouchEvent()方法里, * 如果水平移动距离大于竖直移动距离,ScrollView不拦截这个事件 * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { float currentX=ev.getX(); float currentY=ev.getY(); switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: preX=currentX; preY=currentY; isViewPagerDragged=false; break; case MotionEvent.ACTION_MOVE: if(isViewPagerDragged){ return false; } float dx=Math.abs(preX-currentX); float dy=Math.abs(preY-currentY); if(dx>dy && dx>touchSlop){ isViewPagerDragged=true; return false; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: isViewPagerDragged=false; break; } return super.onInterceptTouchEvent(ev); }}
public class CustomViewPager extends ViewPager { private Map<Integer, Integer> map = new HashMap<>(); private int currentPage; public CustomViewPager(Context context) { this(context, null); } public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); } private int measureHeight(int measureSpec, View view) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { if (view != null) { result = view.getMeasuredHeight(); } if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } Log.d("customviewpager", " measureheight " + result); return result; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//// View view = getChildAt(getCurrentItem());// if (view != null) {// view.measure(widthMeasureSpec, heightMeasureSpec);// }// setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, view));//// int height = 0;// if (map.size() > 0 && map.containsKey(currentPage)) {// height = map.get(currentPage);// }//// //得到ViewPager的MeasureSpec,使用固定值和MeasureSpec.EXACTLY,// heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);// super.onMeasure(widthMeasureSpec, heightMeasureSpec); int height = 0; //下面遍历所有child的高度 Log.d("CustomViewPager","子viewpager的个数"+getChildCount()); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec,MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); Log.d("CustomViewPager","子viewpager高度"+h); map.put(i,h); } if (map.size() > currentPage) { height = map.get(currentPage); } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec);// int height = 0;// for (int i = 0; i < getChildCount(); i++) {// View child = getChildAt(i);// child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));// int h = child.getMeasuredHeight();// Log.d("CustomViewPager", i + "子viewpager高度" + h);// if (h > height)// height = h;// }//// heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);//// super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 在切换tab的时候,重置ViewPager的高度 * * @param current */ public void resetHeight(int current) { this.currentPage = current; MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); if (map.size() > currentPage) { if (params == null) { params = new MarginLayoutParams(LayoutParams.MATCH_PARENT, map.get(current)); } else { params.height = map.get(current); } Log.d("CustomViewPager", current + " " + params.height + ""); this.setLayoutParams(params); } } /** * 获取、存储每一个tab的高度,在需要的时候显示存储的高度 * * @param current tab的position * @param height 当前tab的高度 */ public void addHeight(int current, int height) { map.put(current, height); }}
在activity中显示viewpager时要实现viewpager的监听,在监听中调用resetHeight()方法,实时更新viewpager高度。
mViewpagerHome.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { mMagicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels);// mFragmentList.get(position).setRecyclerviewReplyPull(); } @Override public void onPageSelected(int position) { mMagicIndicator.onPageSelected(position);// mFragmentList.get(position).setRecyclerviewReplyPull(); mViewpagerHome.resetHeight(position);// mViewpagerHome.requestLayout(); mPosition = position; } @Override public void onPageScrollStateChanged(int state) { mMagicIndicator.onPageScrollStateChanged(state); } });
我们的recyclerView有多个layoutmanager,通过重写layoutmanager的方法就可以让recyclerView和ScrollView嵌套了。但是请注意,如果recyclerView很长那么强烈不建议去做嵌套,因为这样recyclerView会在展示的时候立刻展示所有内容,效率极低。
1.LinearLayoutManager和ScrollView嵌套
package com.frankzhu.recyclerviewdemo;import android.content.Context;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.View;import android.view.ViewGroup;/** * Author: ZhuWenWu * Version V1.0 * Date: 2015/2/26 14:15. * Description: * Modification History: * Date Author Version Description * ----------------------------------------------------------------------------------- * 2015/2/26 ZhuWenWu 1.0 1.0 * Why & What is modified: */public class FullyLinearLayoutManager extends LinearLayoutManager { private static final String TAG = FullyLinearLayoutManager.class.getSimpleName(); public FullyLinearLayoutManager(Context context) { super(context); } public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); Log.i(TAG, "onMeasure called. \nwidthMode " + widthMode + " \nheightMode " + heightSpec + " \nwidthSize " + widthSize + " \nheightSize " + heightSize + " \ngetItemCount() " + getItemCount()); int width = 0; int height = 0; for (int i = 0; i < getItemCount(); i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); if (getOrientation() == HORIZONTAL) { width = width + mMeasuredDimension[0]; if (i == 0) { height = mMeasuredDimension[1]; } } else { height = height + mMeasuredDimension[1]; if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { try { View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } finally { } }}
2.GridLayoutManager和ScrollView进行嵌套
package com.frankzhu.recyclerviewdemo;import android.content.Context;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;/** * Author: ZhuWenWu * Version V1.0 * Date: 2015/2/26 14:14. * Description: * Modification History: * Date Author Version Description * ----------------------------------------------------------------------------------- * 2015/2/26 ZhuWenWu 1.0 1.0 * Why & What is modified: */public class FullyGridLayoutManager extends GridLayoutManager { public FullyGridLayoutManager(Context context, int spanCount) { super(context, spanCount); } public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; int count = getItemCount(); int span = getSpanCount(); for (int i = 0; i < count; i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); if (getOrientation() == HORIZONTAL) { if (i % span == 0) { width = width + mMeasuredDimension[0]; } if (i == 0) { height = mMeasuredDimension[1]; } } else { if (i % span == 0) { height = height + mMeasuredDimension[1]; } if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: width = widthSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { if (position < getItemCount()) { try { View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } } }}
3.StaggeredGridLayoutManager和ScrollView进行嵌套
package com.kale.waterfalldemo.extra.RecyclerView;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.View;import android.view.ViewGroup;/** * @author Jack Tony * @brief 不规则排列(类似于瀑布流)的布局管理器 * @date 2015/4/6 */public class ExStaggeredGridLayoutManager extends StaggeredGridLayoutManager { public ExStaggeredGridLayoutManager(int spanCount, int orientation) { super(spanCount, orientation); } // 尺寸的数组,[0]是宽,[1]是高 private int[] measuredDimension = new int[2]; // 用来比较同行/列那个item罪宽/高 private int[] dimension; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { // 宽的mode+size final int widthMode = View.MeasureSpec.getMode(widthSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); // 高的mode + size final int heightMode = View.MeasureSpec.getMode(heightSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); // 自身宽高的初始值 int width = 0; int height = 0; // item的数目 int count = getItemCount(); // item的列数 int span = getSpanCount(); // 根据行数或列数来创建数组 dimension = new int[span]; for (int i = 0; i < count; i++) { measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), measuredDimension); // 如果是竖直的列表,计算item的高,否则计算宽度 //Log.d("LISTENER", "position " + i + " height = " + measuredDimension[1]); if (getOrientation() == VERTICAL) { dimension[findMinIndex(dimension)] += measuredDimension[1]; } else { dimension[findMinIndex(dimension)] += measuredDimension[0]; } } if (getOrientation() == VERTICAL) { height = findMax(dimension); } else { width = findMax(dimension); } switch (widthMode) { // 当控件宽是match_parent时,宽度就是父控件的宽度 case View.MeasureSpec.EXACTLY: width = widthSize; break; case View.MeasureSpec.AT_MOST: break; case View.MeasureSpec.UNSPECIFIED: break; } switch (heightMode) { // 当控件高是match_parent时,高度就是父控件的高度 case View.MeasureSpec.EXACTLY: height = heightSize; break; case View.MeasureSpec.AT_MOST: break; case View.MeasureSpec.UNSPECIFIED: break; } // 设置测量尺寸 setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { // 挨个遍历所有item if (position < getItemCount()) { try { View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException if (view != null) { RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), lp.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), lp.height); // 子view进行测量,然后可以通过getMeasuredWidth()获得测量的宽,高类似 view.measure(childWidthSpec, childHeightSpec); // 将item的宽高放入数组中 measuredDimension[0] = view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; recycler.recycleView(view); } } catch (Exception e) { e.printStackTrace(); } } } private int findMax(int[] array) { int max = array[0]; for (int value : array) { if (value > max) { max = value; } } return max; } /** * 得到最数组中最小元素的下标 * * @param array * @return */ private int findMinIndex(int[] array) { int index = 0; int min = array[0]; for (int i = 0; i < array.length; i++) { if (array[i] < min) { min = array[i]; index = i; } } return index; } }
文中很多地方借鉴了一些博客,还未来得及注明就发了出来,没办法激动之情溢于言表,好多天的bug解决了
阅读全文
0 0
- ScrollView嵌套Viewpager嵌套瀑布流Recyclerview
- RecyclerView 瀑布流 嵌套ScrollView解决方案
- scrollview嵌套RecyclerView嵌套EditText
- ScrollView嵌套RecyclerView
- ScrollView嵌套recyclerView问题
- android ScrollView嵌套RecyclerView
- Scrollview 嵌套 RecyclerView
- scrollview嵌套recyclerview 问题
- scrollview嵌套recyclerview
- ScrollView嵌套RecyclerView 问题
- RecyclerView和ScrollView嵌套
- android ScrollView嵌套RecyclerView
- RecyclerView嵌套问题ScrollView
- ScrollView嵌套RecyclerView
- ScrollView嵌套recyclerView问题
- Scrollview嵌套RecyclerView
- RecyclerView 与 ScrollView嵌套
- ScrollView嵌套recyclerView问题
- Android轻松实现RecyclerView悬浮条
- 网易校招笔试-序列逆序问题
- Spring的applicationContext.xml配置文件的一些问题
- java练习——更新会员积分
- 频道管理的依赖实现
- ScrollView嵌套Viewpager嵌套瀑布流Recyclerview
- Arrays.asList()方法
- 闵可夫斯基距离(MinkowskiDistance)
- VS code 中的各种变量 ${file},${fileBasename}
- XML解析精讲
- MVP + okHttpUtils的简单实践
- netty之ChannelOption
- 未分类
- Django学习(7):templates过滤器及Admin增强