总结
本文讲解了我对Android开发现状的一些看法,也许有些人会觉得我的观点不对,但我认为没有绝对的对与错,一切交给时间去证明吧!愿与各位坚守的同胞们互相学习,共同进步!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
onDraw(c, parent);
}
@Deprecated
public void onDraw(Canvas c, RecyclerView parent) {
}
/**
- 绘制除Item内容以外的东西,这个方法是在Item的内容绘制之后才执行的,
- 所以该方法绘制的东西会将Item的内容覆盖住,既显示在Item之上.
- 一般配合getItemOffsets来绘制分组的头部等.
- @param c Canvas 画布
- @param parent RecyclerView
- @param state RecyclerView的状态
*/
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
/**
- @deprecated
- Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
*/
@Deprecated
public void onDrawOver(Canvas c, RecyclerView parent) {
}
/**
- @deprecated
- Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
*/
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
/**
- 设置Item的布局四周的间隔.
- @param outRect 确定间隔 Left Top Right Bottom 数值的矩形.
- @param view RecyclerView的ChildView也就是每个Item的的布局.
- @param parent RecyclerView本身.
- @param state RecyclerView的各种状态.
*/
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
}
这里面呢有个问题一定要明白几个问题:
- getItemOffsets这个方法设置的Item间隔到底是那个间隔?
我们来看一张图.
我们知道getItemOffsets()第一个参数是一个矩形的对象,这个对象的left、 top、right、bottpm四个属性值分别表示图中的outRect.left、outRect.top、outRect.right、outRect.bottom四个线段所表示的空间.也就是说当RecyclerView的Item再确定自己的大小的时候会将getItemOffsets()里面的Rect对象的Left、Top、Right、Bottom属性取出来,看看需要再Item布局的四周留出多大的空间.我们来看下源码:
Rect getItemDecorInsetsForChild(View child) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.mInsetsDirty) {
return lp.mDecorInsets;
}
if (mState.isPreLayout() && (lp.isItemChanged() || lp.isViewInvalid())) {
// changed/invalid items should not be updated until they are rebound.
return lp.mDecorInsets;
}
final Rect insets = lp.mDecorInsets;
insets.set(0, 0, 0, 0);
final int decorCount = mItemDecorations.size();
for (int i = 0; i < decorCount; i++) {
mTempRect.set(0, 0, 0, 0);
//这里呢mTempRect就是我们再getItemOffsets()里面的第一个Rect的对象,我们再实现类的方法里面给mTempRect赋值.
mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState);
insets.left += mTempRect.left;
insets.top += mTempRect.top;
insets.right += mTempRect.right;
insets.bottom += mTempRect.bottom;
}
lp.mInsetsDirty = false;
return insets;
}
这里呢就是RecyclerView再测量每个Child的大小的时候都把insets这个矩形的l t r b 数值都加上了.insets就是方法getItemDecorInsetsForChild()返回的矩形对象.
/**
- Measure a child view using standard measurement policy, taking the padding
- of the parent RecyclerView and any added item decorations into account.
-
If the RecyclerView can be scrolled in either dimension the caller may
- pass 0 as the widthUsed or heightUsed parameters as they will be irrelevant.
- @param child Child view to measure
- @param widthUsed Width in pixels currently consumed by other views, if relevant
- @param heightUsed Height in pixels currently consumed by other views, if relevant
*/
public void measureChild(View child, int widthUsed, int heightUsed) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
widthUsed += insets.left + insets.right;
heightUsed += insets.top + insets.bottom;
final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
getPaddingLeft() + getPaddingRight() + widthUsed, lp.width,
canScrollHorizontally());
final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
getPaddingTop() + getPaddingBottom() + heightUsed, lp.height,
canScrollVertically());
if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) {
child.measure(widthSpec, heightSpec);
}
}
源码的讲解过于粗糙,希望大家见谅,目的就是为了让大家知道这个getItemOffsets()方法是怎么让RecyclerView再Item之外留出空间的.
- onDraw()和onDrawOver()方法应该用哪一个?
首先我们看过上面的代码之后知道,onDraw执行再Item的绘制之前,也就是ItemDecoration的onDraw方法先执行,再执行Item的onDraw方法,这样Item的内容就会覆盖在ItemDecoration的onDraw上面.ItemDecoration的onDrawOver()方法执行在Item的绘制之后,那就是onDrawOver()绘制的内容会覆盖再Item内容之上.这样就形成了层层遮盖的问题,那么我们平常的分割线通常绘制在ItemDecoration的onDraw()方法里面,为了避免Item的内容覆盖掉,我们就要getItemOffsets()为我们留出绘制的空间了.这样我们的思路不是不有了呢.
我们可以用onDrawOver()和getItemOffsets()方法一起使用来实现Item的粘性头部和顶部悬浮的效果.
三 代码部分
需求分析:这部分其实是写代码前尤为重要的一部分,再分析的过程中你可以知道我们要完成的是哪些功能,用什么东西去完成,怎么才能更好的去完成.最后自己能确定出一套完美实现需求的方案.
我们要做的是区域分组显示,每个分组的开始要有一个粘性头部.如图所示:
- 数据准备
首先后台返回的数据一定要有组类区分,每个分组的标记不能一样,最好是我们方便处理的.该Demo采用的标记位是int类型的标记tag,每组的标记以此+1,每五个城市分为一组,每组的第一个城市当做头部局显示的内容.我们的分组头部的高度为40dp.
- getItemOffsets()
该方法再recyclerView的每个Item测量大小的时候都会被调用到, 我们要在该方法里面判断出那个HeadItem并且给HeadItem留出绘制的空间,这里有两种方式.
第一种方式:
给Item 的Top留出空间,也就是outRect.top属性赋值.
第二种方式:
给Item 的Bottom留出空间也就是outRect.bottpm属性赋值.
因为我们在列表一开始的时候就要绘制一次Head,也就是说我们要留出Head的空间,那么我们只能选择第一种方法去预留空间了. 当你选择方式1的时候,给outRect.top赋值,这样的话我们判断是否是HeadItem的话就要拿当前Item的标记跟前一个Item的标记判断了.如果用第二种的话就要用当前的标记跟下一个Item的标记判断了.
下面我来解释下第一种方式,第二种方式雷同:
a b c d e f g h i
分组1 abc
分组2 def
分组3 ghi
如果 a d g 是HeadItem . a的tag = 1 , b的tag = 1, c 的tag = 1…d的tag = 2,e的tag = 2 ,f的tag = 2,g的tag = 3…等等 .
前一个Item的tag用 preTag 来表示 ,初始值为 -1.
假如当前的Item为a,当前tag = 1,那么它的前一个Item为空,也就是发现preTag和a的tag不一样,那么a就是分组的头部.
假如当前的Item为b,当前tag = 1,那么它前一个preTag 也就是a的tag = 1,发现一样那就是是同一组的.
假如当前的Item为d,当前tag = 2,那么它前一个preTag 也就是c的tag = 1,发现前一个的tag跟当前的不一样,那么当前的就是新分组的第一个头部Item.代码是最有说服力的,下面来看代码:
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (citiList == null || citiList.size() == 0) {
return;
}
int adapterPosition = parent.getChildAdapterPosition(view);
RecBean.CitiListBean beanByPosition = getBeanByPosition(adapterPosition);
if(beanByPosition == null){
return;
}
int preTage = -1;
int tage = beanByPosition.getTage();
//一定要记住这个 >= 0
if(adapterPosition - 1 >= 0) {
RecBean.CitiListBean nextBean = getBeanByPosition(adapterPosition - 1);
if (nextBean == null) {
return;
}
最后
针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
-
Android前沿技术大纲
-
全套体系化高级架构视频
Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!