RecyclerView的ItemDecoration总结
2017-09-06 本文已影响384人
西西邱
一、RecyclerView.ItemDecoration 基本用法
public class TestDividerItemDecoration extends RecyclerView.ItemDecoration {
// 方法1:getItemOffsets (每出现一个position,调用一次)
// 作用:设置ItemView的内嵌偏移长度(inset),相当于增加itemview的paddingLeft,paddingTop, paddingRight, paddingBottom
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
//获取当前item位置
//int position = parent.getChildAdapterPosition(view);
//获取item数目
//int itemCount = parent.getAdapter().getItemCount();
if (mOrientation == VERTICAL){
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
// 作用:在绘制itemView之前,通过一系列c.drawXXX()方法绘制我们需要的内容
// 绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL){
drawVertical(c,parent,state);
}else {
drawHorizontal(c,parent,state);
}
}
private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state) {
c.save();//保存Canvas
int left;
int right;
//getClipToPadding是否限制在Padding绘制item--默认=true
if (parent.getClipToPadding()){
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
c.clipRect(left, parent.getPaddingTop(), right,parent.getHeight()- parent.getPaddingBottom());
}else {
left = 0;
right = parent.getWidth();
}
//绘制
int itemCount = parent.getChildCount();
for (int i = 0; i < itemCount; i++) {
View childAt = parent.getChildAt(i);
/* getDecoratedBoundsWithMargins点进去的源码
* mBounds.left = view.getLeft() - insets.left - lp.leftMargin
* view.getLeft() == itemView的左边距横坐标
* insets.left() == itemView所有Decoration left 之和
* lp.leftMargin == itemView的MarginLeft的大小
*/
parent.getDecoratedBoundsWithMargins(childAt,mBounds);
/*mBounds.bottom == itemView底坐标+ insets.bottom()(Decoration bottom之和)+ itemView的MarginBottom
*Math.round(ViewCompat.getTranslationY(childAt))
*/
int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(childAt));
int top = bottom - mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
c.restore();
}
// 作用:onDrawOver与onDraw类似,只不过在绘制itemView之后绘制,具体表现形式,就是绘制的内容在itemview上层。
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
Log.e(TAG, "onDrawOver" );
}
}
二、RecyclerView时光轴效果
菜鸟裹裹时光轴效果:地址
三、微信通讯录分组悬浮效果
RecyclerView悬浮效果(代码少容易理解):地址
RecyclerView悬停头部的分组列表(进阶):地址
四、一个BUG
注意:做一个一个小实验
代码:我们设置ItemView的outRect四个方向上的偏移量
public void getItemOffsets(){
int positionB = parent.getChildAdapterPosition(view);
//只给B位置设置偏移量
if (positionB == 1){
//四个方向上偏移量都是100
outRect.set(100,100,100,100);
}
}
运行结果:如下图(这里的Orientation为LinearLayoutManager.VERTICAL)
QQ截图20170906144948.png注意看B的宽高
结论:getItemOffsets()方法设置ItemView内嵌矩形偏移值会导致
1、不能滑动方向上ItemView的长度被压缩
2、能滑动方向上ItemView的长度不变
我们看下RecyclerView的measureChild()源码找答案:
**RecyclerView**
public void measureChild(View child, int widthUsed, int heightUsed) {
...
//这里Child的宽高和canScroll(该方向能否滑动)有关,具体的测量方式可以自己去看
final int widthSpec = getChildMeasureSpec(..., boolean canScroll);
final int heightSpec = getChildMeasureSpec(..., boolean canScroll);
...
child.measure(widthSpec, heightSpec);
}