Scrollview嵌套Recyclerview出现的显示不全 不显示问题的解决方法
2017-06-28 10:21
561 查看
原文连接
公司项目需要用到一个scrollview里面嵌套上下两个垂直的recyclerview 上面的recyclerview能够显示全 下面的recyclerview显示不全 在网上找了许多方案 都差不多 知道找到了上面的文章 完美解决
如果有兴趣可以去看一下原文 下面我直接撸上我的解决代码了 分了三步 重写recyclerview 重写LinearLayoutManager 在activity里面调用
最后使用
然后完美解决
补充一下 完成之后 scrollview的滑动不流畅 有种粘滞感觉 需要重写一下scrollview里面的onInterceptTouchEvent方法
公司项目需要用到一个scrollview里面嵌套上下两个垂直的recyclerview 上面的recyclerview能够显示全 下面的recyclerview显示不全 在网上找了许多方案 都差不多 知道找到了上面的文章 完美解决
如果有兴趣可以去看一下原文 下面我直接撸上我的解决代码了 分了三步 重写recyclerview 重写LinearLayoutManager 在activity里面调用
public class MyRecyclerView extends RecyclerView { public MyRecyclerView(Context context) { super(context); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthSpec, int heightSpec) { int height = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthSpec, height); } }
/** * 重写 LinearLayoutManager 为了ScrollView可以显示RecyclerView 垂直布局 * * @author M.Z */ public class FullyLinearLayoutManager extends LinearLayoutManager { private static boolean canMakeInsetsDirty = true; private static Field insetsDirtyField = null; private static final int CHILD_WIDTH = 0; private static final int CHILD_HEIGHT = 1; private static final int DEFAULT_CHILD_SIZE = 100; private final int[] childDimensions = new int[2]; private final RecyclerView view; private int childSize = DEFAULT_CHILD_SIZE; private boolean hasChildSize; private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS; private final Rect tmpRect = new Rect(); public FullyLinearLayoutManager(Context context) { super(context); this.view = null; } public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); this.view = null; } public FullyLinearLayoutManager(RecyclerView view) { super(view.getContext()); this.view = view; this.overScrollMode = ViewCompat.getOverScrollMode(view); } public FullyLinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) { super(view.getContext(), orientation, reverseLayout); this.view = view; this.overScrollMode = ViewCompat.getOverScrollMode(view); } public void setOverScrollMode(int overScrollMode) { if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER) throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode); if (this.view == null) throw new IllegalStateException("view == null"); this.overScrollMode = overScrollMode; ViewCompat.setOverScrollMode(view, overScrollMode); } public static int makeUnspecifiedSpec() { return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); } @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); final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED; final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED; final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY; final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY; final int unspecified = makeUnspecifiedSpec(); if (exactWidth && exactHeight) { // in case of exact calculations for both dimensions let's use default "onMeasure" implementation super.onMeasure(recycler, state, widthSpec, heightSpec); return; } final boolean vertical = getOrientation() == VERTICAL; initChildDimensions(widthSize, heightSize, vertical); int width = 0; int height = 0; // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never // called whil e6c7 es scrolling) recycler.clear(); final int stateItemCount = state.getItemCount(); final int adapterItemCount = getItemCount(); // adapter always contains actual data while state might contain old data (f.e. data before the animation is // done). As we want to measure the view with actual data we must use data from the adapter and not from the // state for (int i = 0; i < adapterItemCount; i++) { if (vertical) { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items // we will use previously calculated dimensions measureChild(recycler, i, widthSize, unspecified, childDimensions); } else { logMeasureWarning(i); } } height += childDimensions[CHILD_HEIGHT]; if (i == 0) { width = childDimensions[CHILD_WIDTH]; } if (hasHeightSize && height >= heightSize) { break; } } else { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items // we will use previously calculated dimensions measureChild(recycler, i, unspecified, heightSize, childDimensions); } else { logMeasureWarning(i); } } width += childDimensions[CHILD_WIDTH]; if (i == 0) { height = childDimensions[CHILD_HEIGHT]; } if (hasWidthSize && width >= widthSize) { break; } } } if (exactWidth) { width = widthSize; } else { width += getPaddingLeft() + getPaddingRight(); if (hasWidthSize) { width = Math.min(width, widthSize); } } if (exactHeight) { height = heightSize; } else { height += getPaddingTop() + getPaddingBottom(); if (hasHeightSize) { height = Math.min(height, heightSize); } } setMeasuredDimension(width, height); if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) { final boolean fit = (vertical && (!hasHeightSize || height < heightSize)) || (!vertical && (!hasWidthSize || width < widthSize)); ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS); } } private void logMeasureWarning(int child) { // if (BuildConfig.DEBUG) { // Log.w("LinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." + // "To remove this message either use #setChildSize() method or don't run RecyclerView animations"); // } } private void initChildDimensions(int width, int height, boolean vertical) { if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) { // already initialized, skipping return; } if (vertical) { childDimensions[CHILD_WIDTH] = width; childDimensions[CHILD_HEIGHT] = childSize; } else { childDimensions[CHILD_WIDTH] = childSize; childDimensions[CHILD_HEIGHT] = height; } } @Override public void setOrientation(int orientation) { // might be called before the constructor of this class is called //noinspection ConstantConditions if (childDimensions != null) { if (getOrientation() != orientation) { childDimensions[CHILD_WIDTH] = 0; childDimensions[CHILD_HEIGHT] = 0; } } super.setOrientation(orientation); } public void clearChildSize() { hasChildSize = false; setChildSize(DEFAULT_CHILD_SIZE); } public void setChildSize(int childSize) { hasChildSize = true; if (this.childSize != childSize) { this.childSize = childSize; requestLayout(); } } private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) { final View child; try { child = recycler.getViewForPosition(position); } catch (IndexOutOfBoundsException e) { // if (BuildConfig.DEBUG) { // Log.w("LinearLayoutManager", "LinearLayoutManager doesn't work well with animations. Consider switching them off", e); // } return; } final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams(); final int hPadding = getPaddingLeft() + getPaddingRight(); final int vPadding = getPaddingTop() + getPaddingBottom(); final int hMargin = p.leftMargin + p.rightMargin; final int vMargin = p.topMargin + p.bottomMargin; // we must make insets dirty in order calculateItemDecorationsForChild to work makeInsetsDirty(p); // this method should be called before any getXxxDecorationXxx() methods calculateItemDecorationsForChild(child, tmpRect); final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child); final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child); final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally()); final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically()); child.measure(childWidthSpec, childHeightSpec); dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin; dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin; // as view is recycled let's not keep old measured values makeInsetsDirty(p); recycler.recycleView(child); } private static void makeInsetsDirty(RecyclerView.LayoutParams p) { if (!canMakeInsetsDirty) { return; } try { if (insetsDirtyField == null) { insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty"); insetsDirtyField.setAccessible(true); } insetsDirtyField.set(p, true); } catch (NoSuchFieldException e) { onMakeInsertDirtyFailed(); } catch (IllegalAccessException e) { onMakeInsertDirtyFailed(); } } private static void onMakeInsertDirtyFailed() { canMakeInsetsDirty = false; // if (BuildConfig.DEBUG) { // Log.w("LinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect"); // } } }
最后使用
// recyclerview1.setLayoutManager(new LinearLayoutManager(this, LinearLayout.VERTICAL, false)); recyclerview1.setLayoutManager(new FullyLinearLayoutManager(this)); newAdapter = new NewCustomerGetCouponsAdapter(this); recyclerview1.setAdapter(newAdapter); recyclerview1.addItemDecoration(new HorzitalSpacesItemDecoration(20)); // recyclerview2.setLayoutManager(new LinearLayoutManager(this, LinearLayout.VERTICAL, false)); recyclerview2.setLayoutManager(new FullyLinearLayoutManager(this)); normalAdapter = new NormalGetCouponsAdapter(this); recyclerview2.setAdapter(normalAdapter); recyclerview2.addItemDecoration(new HorzitalSpacesItemDecoration((int) getResources().getDimension(R.dimen.y20)));
然后完美解决
补充一下 完成之后 scrollview的滑动不流畅 有种粘滞感觉 需要重写一下scrollview里面的onInterceptTouchEvent方法
/** * 屏蔽内部recyclerview的滑动事件 * @param e * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent e) { int action = e.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: downX = (int) e.getRawX(); downY = (int) e.getRawY(); break; case MotionEvent.ACTION_MOVE: int moveY = (int) e.getRawY(); if (Math.abs(moveY - downY) > mTouchSlop) { return true; } } return super.onInterceptTouchEvent(e); }
相关文章推荐
- 解决ScrollView嵌套RecyclerView出现item显示不全的问题
- 两种方法解决ScrollView嵌套ListView出现ListView显示不全的问题
- 解决ScrollView嵌套RecyclerView出现item显示不全的问题
- 解决 通过继承QAbstractTableModel并实现headerData方法给QTableView添加标题时,标题不显示 的问题
- 固定宽度下拉列表中option内容显示不全问题解决方法
- ie11兼容性问题,jsp在IE11显示不全问题,ie11覆盖内容问题解决方法
- php读取csv文件后,uft8 bom导致在页面上显示出现问题的解决方法
- ANDROID Recycleview notifyDataSetChanged()方法调用出现IllegalStateException 问题的解决
- Fragment中包含surfaceView出现闪屏问题解决方法
- 没有滚动条,页面内容显示不全问题的解决方法
- html固定宽度下拉框内容显示不全问题解决方法
- iphone--设置UITextView内边距,解决textView内容显示不全的问题
- 使用View.getWidth()方法出现的问题及解决方法
- vs2008与IIS 7.0使用在vista上时出现的问题及解决方法(Internet Explorer 无法显示该页面)(VS2008: IE Cannot Display Web Page)
- listview 放入 scrollview出现显示问题的解决方法
- 固定宽度下拉列表中option内容显示不全问题解决方法
- .NET:关于byte数组在用StreamWriter文件写出后出现多余字符的解决方法及VS方案文件图标显示问题
- smarty作为view时使用Zend_Form出现方法未定义的问题原因及解决
- 固定宽度下拉列表中option内容显示不全问题解决方法
- 固定宽度下拉列表中option内容显示不全问题解决方法