美文网首页新的开始新收藏
1.Android recycleView万能分隔线

1.Android recycleView万能分隔线

作者: 鹏城十八少 | 来源:发表于2021-06-26 10:23 被阅读0次

    从月薪3000到年薪60万。从专科生到深圳一线大厂。关注我就能达到大师级水平,这话我终于敢说了, 年薪60万不是梦!

    今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等

    RecyclerView的分割线是通过canvas和设置item偏移画出来的.需要知道2个方法

    getItemOffsets()和onDraw方法

    getItemOffsets 是针对每一个 ItemView

    onDraw:遍历,进行颜色修改

    我们可以看到自定义的 TestDividerItemDeoration 只实现了一个方法 getItemOffsets()。方法里面有四个参数。

    Rect outRect

    View view

    RecyclerView parent

    RecyclerView.State state

    绿色区域代表 RecyclerView 中的一个 ItemView,而外面橙色区域也就是相应的 outRect,也就是 ItemView 与其它组件的偏移区域,等同于 margin 属性,通过复写 getItemOffsets() 方法,然后指定 outRect 中的 top、left、right、bottom 就可以控制各个方向的间隔了。

    这实现了简单的分隔线效果,但这种方法分隔线的效果只能取决于背景色,如果我要定制分割线的颜色呢?这个时候就要 onDraw()。

    ————————————————

    源码分析:在recycleview中的

    分割线要注意,没有颜色,默认是白色的,会看不出来

    第一种方案,通过

    getItemOffsets()方法进行分割线!

    判断是否是第一个,最后一个,是单个还是双个,是什么类型

    /***

    * 分割线要注意,没有颜色,默认是白色的,会看不出来

    * @param outRect

    * @param view

    * @param parent

    * @param state

    */

    private void testItemOffset(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

    int childAdapterPosition = parent.getChildAdapterPosition(view);

        if (childAdapterPosition ==0) {

    outRect.set(0, 20, 0, 20);

        }else {

    outRect.set(0, 0, 0, 20);

        }

    }

    第二种方案:ondraw()

    @Override

    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {

    super.onDraw(c, parent, state);

        int childCount = parent.getChildCount();

        for (int i =0; i < childCount; i++) {

    View view = parent.getChildAt(i);

            int index = parent.getChildAdapterPosition(view);

            //第一个ItemView不需要绘制

            if (index ==0) {

    continue;

            }

    float dividerTop = view.getTop() -mDividerHeight;

            float dividerLeft = parent.getPaddingLeft();

            float dividerBottom = view.getTop();

            float dividerRight = parent.getWidth() - parent.getPaddingRight();

            c.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);

        }

    }

     GridLayoutManager布局item左右间距均等

    思路分析

    首先,我们知道,对于 GridLayoutmanager ,当我们设置的 spancount 为 3 的时候,那么每个 item 的最大宽度为 itemMaxW = recycylerW / spancount = recycylerW / 3.

    假设我们 spancount 为 3,那么在不设置 itemDercation 的情况下它的分布是这样的,可以看到第一列与最后一行的距离是不一样的

    GridVIew出现的问题:本来固定item.高度和宽度

    1.分割线有,不是理想的,左右均等

    2.上下没有分割线

    源码得到:

    按上面分析的源码,我们可以知道,调用outRect.set(int left, int top, int right, int bottom)方法时,left一直为0,right一直为divider的宽度,而每一项item的宽度都要减去(left+right)大小,

    left一直为0,right一直为divider的宽度

    左上右下到底是什么的值?

    计算每一个item移动的距离,左边和右边的移动距离

    计算分析:

    1.左边的分割线宽度为sW  (已知)

    2.每个显示item的宽度,布局定义的itemWidth

    3. 总共分割线宽度:totalDivider=屏幕宽度-spanCount*itemWidth

    4.列之间的分割线宽度为dw   =(屏幕宽度-spanCount*item-2*sW )/(spantcount-1)

    5.每个item需要留出的空间 ew=totalDivider/spanCount(即paddingLeft+paddingRight)

    left:  左边的间距值(绝对值,差值)

    right:右边的间距值

    每个item移动的距离:

    第一个Item:L0=sW                                  R0=eW-sW

    第二个Item:L1=dW-R0=dW-eW+sW       R1=eW-L1=2eW-dW-sW

    第三个Item:L2=dW-R1=2(dW-eW)+sW   R2=eW-L2=3eW-2dW-sW

    得出公式:

    Ln=(position%spanCount)*(dw-ew)+sw

    Rn=ew-Ln

    总结:得到3个值dw,ew, sw的值

    sw:左边的距离

    ew:每个的平均的分割线

    dw: 列之间的分割线宽度

    int firstLastSpace =50;//最左边的分割线宽度

    @SuppressLint("LongLogTag")

    @Override

    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

    super.getItemOffsets(outRect, view, parent, state);

        count++;

        outRect.top =20;

        mDividerHeight =0;

        int itemWidth =dip2px(context, 100);

        int screenWidth = getScreenWidth(context);

        int dw = (screenWidth -3 * itemWidth -2 *firstLastSpace) /2;//最终计算出这个padding值

        //误区:中间的分割线的总距离,左右可能是不等的

        int totalDivder = screenWidth -3 * itemWidth;

        Log.d("TestDividerItemDecoration", "totalDivder" + totalDivder);

        int eachDivder = totalDivder /3;

        int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();

        //不要用for循环

        outRect.left = (itemPosition %3) * (dw - eachDivder) +firstLastSpace;

        outRect.right = eachDivder - outRect.right;

    }

    错误的思路:

    //误区:中间的分割线的总距离,左右可能是不等的

    //不要用for循环

    int firstLastSpace =50;//最左边的分割线宽度

    @SuppressLint("LongLogTag")

    @Override

    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

    super.getItemOffsets(outRect, view, parent, state);

        count++;

        outRect.top =20;

        mDividerHeight =0;

        int itemWidth =dip2px(context, 100);

        int screenWidth = getScreenWidth(context);

        int padding = (screenWidth -3 * itemWidth -2 *firstLastSpace) /4;//最终计算出这个padding值

        //不能这么算,必须保证每个item的分割线一样才行。

        Log.d("TestDividerItemDecoration", "getItemOffsets" +count +"item宽度:" + itemWidth +"padding" + padding);

        //仅仅计算左边和右边的距离

        int childCount = parent.getChildCount();

        for (int i =0; i < childCount; i++) {

    if (i %3 ==0) {//最左边的item

                outRect.left =firstLastSpace;

                outRect.right = padding;

            }else if (i %3 ==1) {

    outRect.left = padding;

                outRect.right = padding;

            }else if (i %3 ==2) {

    outRect.left = padding;

                outRect.right =firstLastSpace;

            }

    }

    }

    瀑布流的设置:

    int spanIndex = layoutParams.getSpanIndex();

    public class FeedDecorationextends RecyclerView.ItemDecoration {

    private HomePageCardAdaptermHomePageCardAdapter;

        public FeedDecoration(HomePageCardAdapter mHomePageCardAdapter) {

    this.mHomePageCardAdapter = mHomePageCardAdapter;

        }

    @Override

        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {

    if (mHomePageCardAdapter ==null) {

    return;

            }

    if (mHomePageCardAdapter.getItemViewType(parent.getChildAdapterPosition(view)) == HomePageMultipleCard.HOMEPAGE_MULTIPLE_CARD_TYPE_FITNESS_FEED) {

    StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();

                int spanIndex = layoutParams.getSpanIndex();

                if (spanIndex ==0) {

    outRect.set(DensityUtil.dip2px(ShadowApp.context(), 14), 0, DensityUtil.dip2px(ShadowApp.context(), 5), DensityUtil.dip2px(ShadowApp.context(), 10));

                }else {

    outRect.set(DensityUtil.dip2px(ShadowApp.context(), 5), 0, DensityUtil.dip2px(ShadowApp.context(), 14), DensityUtil.dip2px(ShadowApp.context(), 10));

                }

    }

    }

    }

    demo地址:https://github.com/pengcaihua123456/shennandadao

    相关文章

      网友评论

        本文标题:1.Android recycleView万能分隔线

        本文链接:https://www.haomeiwen.com/subject/clzayltx.html