实现GridLayoutManager支持RTL
来源:互联网 发布:知乎 自己拍婚纱照 编辑:程序博客网 时间:2024/06/05 22:50
最近在工作中遇见个奇怪现象,即RecyclerView 采用GridLayoutManager进行布局,当系统是LTR时,数据刷新时变现正常;但是如果是RTL情况下,每次数据添加或莫名其妙向上滚动一个单元格。测试提出这个问题后就开始疯狂找问题,最终定位是由于GridLayoutManager内部方法findReferenceChild引起的。
GridLayoutManager源码如下:
View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state, int start, int end, int itemCount) { ensureLayoutState(); View invalidMatch = null; View outOfBoundsMatch = null; final int boundsStart = mOrientationHelper.getStartAfterPadding(); final int boundsEnd = mOrientationHelper.getEndAfterPadding(); final int diff = end > start ? 1 : -1; for (int i = start; i != end; i += diff) { final View view = getChildAt(i); final int position = getPosition(view); if (position >= 0 && position < itemCount) { final int span = getSpanIndex(recycler, state, position); if (span != 0) { continue; } if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) { if (invalidMatch == null) { invalidMatch = view; // removed item, least preferred } } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd || mOrientationHelper.getDecoratedEnd(view) < boundsStart) { if (outOfBoundsMatch == null) { outOfBoundsMatch = view; // item is not visible, less preferred } } else { return view; } } } return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch;}
其中:
final int span = getSpanIndex(recycler, state, position); if (span != 0) { continue; }
span != 0 这个地方有问题,因为发现RTL时取到的值并不是最后显示的view对应的position。找到问题后果断采取措施,重写该方法。
但是发现这个这个方法是包内可见的方法,于是定义类生命包名跟GridLayoutManager包名相同,重新方法findReferenceChild,当RTL时获取spanIndex=mSpanCount-1;
源码如下:
package android.support.v7.widget;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * Created by liuyt on 17-5-9. * to make {@link GridLayoutManager} support RTL , * with fix bug of it that not support RTL very well */public class RTLGridLayoutManager extends GridLayoutManager { private static final boolean DEBUG = false; private static final String TAG = "MyGridLayoutManager"; /** * Constructor used when layout manager is set in XML by RecyclerView attribute * "layoutManager". If spanCount is not specified in the XML, it defaults to a * single column. * * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount */ public RTLGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } /** * Creates a vertical GridLayoutManager * * @param context Current context, will be used to access resources. * @param spanCount The number of columns in the grid */ public RTLGridLayoutManager(Context context, int spanCount) { super(context, spanCount); } /** * @param context Current context, will be used to access resources. * @param spanCount The number of columns or rows in the grid * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link * #VERTICAL}. * @param reverseLayout When set to true, layouts from end to start. */ public RTLGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { super(context, spanCount, orientation, reverseLayout); } @Override View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state, int start, int end, int itemCount) { ensureLayoutState(); View invalidMatch = null; View outOfBoundsMatch = null; final int boundsStart = mOrientationHelper.getStartAfterPadding(); final int boundsEnd = mOrientationHelper.getEndAfterPadding(); final int diff = end > start ? 1 : -1; int index; if (isLayoutRTL()) { index = mSpanCount - 1; } else { index = 0; } for (int i = start; i != end; i += diff) { final View view = getChildAt(i); final int position = getPosition(view); if (position >= 0 && position < itemCount) { final int span = getSpanIndex(recycler, state, position); if (span != index) { continue; } if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) { if (invalidMatch == null) { invalidMatch = view; // removed item, least preferred } } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd || mOrientationHelper.getDecoratedEnd(view) < boundsStart) { if (outOfBoundsMatch == null) { outOfBoundsMatch = view; // item is not visible, less preferred } } else { return view; } } } return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch; } private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) { if (!state.isPreLayout()) { return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount); } final int cached = mPreLayoutSpanIndexCache.get(pos, -1); if (cached != -1) { return cached; } final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos); if (adapterPosition == -1) { if (DEBUG) { throw new RuntimeException("Cannot find span index for pre layout position. It is" + " not cached, not in the adapter. Pos:" + pos); } Log.w(TAG, "Cannot find span size for pre layout position. It is" + " not cached, not in the adapter. Pos:" + pos); return 0; } return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, mSpanCount); }}
0 0
- 实现GridLayoutManager支持RTL
- android的RTL支持
- RTL布局支持
- android RTL布局支持说明
- RTL的实现
- RecyclerView使用GridLayoutManager实现两种item
- Android支持RTL(从右向左)语言
- RecyclerView GridLayoutManager实现复杂的列数变化的布局
- RecyclerView GridLayoutManager实现复杂的列数变化的布局
- RecyclerView利用GridLayoutManager实现少于span数量时候居中对齐
- 串口的RTL实现原理分析
- Android 4.2 支持原生RTL(由右到左显示)
- Android 开发:如何让App支持RTL模式
- 设置APP支持阿拉伯(RTL 从右向左)语言
- 【RTL-SDR】用RTL-SDR实现航班追踪(ADS-B)
- Android布局--相对布局,RTL,用代码实现布局
- RecyclerView中利用GridLayoutManager实现item四周都带有分割线效果(更正版!!!)
- RecyclerView在GridLayoutManager情况下实现四周都有分割线的ItemDecoration
- logistic回归
- HTML5动画与动效之一
- 开发可配置portlet--config.jsp
- 使用Python如何生成200个随机码?
- java常用类型转换总结
- 实现GridLayoutManager支持RTL
- Maximum GCD (暴力枚举+输入技巧)
- Android系统服务:WallpagerManager
- mac版本Android Studio2.3 修改默认ConstraintLayout为LinearLayout
- c#中获取服务器IP,客户端IP以及Request.ServerVariables详细说明-->防止SQL的注入
- 给Extjs的GridPanel增加“合计”行
- Java内存模型(JMM)
- 面向对象
- Java面向对象设计模式(十九)——备忘录模式(Memento)