小甜点,RecyclerView 之 ItemDecoration 讲解及高级特性实践

本文详细介绍了如何使用RecyclerView的ItemDecoration来实现界面装饰,包括分割线、时光轴效果和角标。通过自定义getItemOffsets()和onDraw()方法,结合onDrawOver()绘制覆盖在ItemView上的内容,实现个性化界面。此外,还预告了如何通过ItemDecoration创建RecyclerView的头部和粘性头部。
摘要由CSDN通过智能技术生成

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

毫无疑问,RecyclerView 是现在 Android 世界中最重要的系统组件之一,它的出现就是为了高效代替 ListView 和 GridView。当时它的出现解决了我一个大的需求,这个需求就是在电视盒子界面上横向加载应用列表,由于 ListView 没有横向加载的功能,而网络上开源的那些 HorizontalListView 又不满足需求,所以我们只能自定义 ViewGroup 来实现需求,但是回收机制不是很完善,所以性能并不好,所以当 RecyclerView 横空出世时,我第一时间拥抱了它,并推荐 Android 开发小组成员们去了解它。

但后来,我发现 RecyclerView 除了比 ListView 好用外,某些地方它却更复杂了,它将更多的权力交给了开发者自己,比如布局,比如 ITEM 的分割线,比如点击监听等等。但总归它是好东西,所以我们得多花些时间来学习,平常开发我们一般按照 RecyclerView 的基本用法便可以实现绝大多数需求,但是某些场景下却远远不够,比如我们不想局限于 LinearLayoutManager 想自己定义 LayoutManager,我们需要定义时光轴的效果,我们想实现美妙的添加删除动画等等,这些情况下解决问题的话需要我们对 RecyclerView 本身有足够的了解。

今天,这篇文章不讲 RecyclerView 基本的知识和用法,讲它一个有趣的知识点 ItemDecoration。

ItemDecoration

Decoration 的英文意思是装饰物的意思,引申到这里来,肯定也是与 RecyclerView 的界面装饰有关。我们常见的就是分割线了。
我们在使用 ListView 的时候只要在 xml 文件中,使用 android:divider 就可以,但是很遗憾 RecyclerView 却没有相应的控制。

我们新建一个工程,然后在一个页面里面添加一个 RecyclerView。创建相关的 Adapter,加载布局文件,这里布局文件很简单,就是一个 TextView,再之后在 Activity 初始化它。

public class DividerActivity extends AppCompatActivity {
   
    RecyclerView mRecyclerView;
    List<String> data;
    TestAdapter mAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_divider);
        mRecyclerView = (RecyclerView) findViewById(R.id.divider_recyclerview);
        initDatas();
        mAdapter = new TestAdapter(data);
        mRecyclerView.setAdapter(mAdapter);
        LinearLayoutManager layoutmanager = new LinearLayoutManager(this);
        layoutmanager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(layoutmanager);
    }

    private void initDatas() {
        data = new ArrayList<>();
        for (int i = 0; i < 56;i++) {
            data.add(i+" test ");
        }
    }
}

这里写图片描述

可以看到所有的选项都混在一起,为了美观应该需要 1 px 的分割线,之前我一般在 Item 的布局文件中设置它的 topMargin 或者是 bottomMargin,所以我们可以在相关的 Adapter 中这样修改。

public TestHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item,parent,false);
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
        layoutParams.topMargin = 1;
        view.setLayoutParams(layoutParams);
        TestHolder holder = new TestHolder(view);
        return holder;
}

效果如下:

这里写图片描述

现在我们同样可以通过给 RecyclerView 添加 ItemDecoration 来实现它。

首先,我们需要自定义一个 ItemDecoration,按照目前的需求,我们只需要实现它的一个方法就可以了。

public class TestDividerItemDecoration extends RecyclerView.ItemDecoration {
   

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

//        //如果不是第一个,则设置top的值。
        if (parent.getChildAdapterPosition(view) != 0){
            //这里直接硬编码为1px
            outRect.top = 1;
        }
    }
}

然后在 Activity 中添加它到 RecyclerView 就可以了。

mRecyclerView = (RecyclerView) findViewById(R.id.divider_recyclerview);
initDatas();
mAdapter = new TestAdapter(data);
mRecyclerView.setAdapter(mAdapter);
LinearLayoutManager layoutmanager = new LinearLayoutManager(this);
layoutmanager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutmanager);
mRecyclerView.addItemDecoration(new TestDividerItemDecoration());

效果如图:

这里写图片描述

getItemOffsets()

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

  • Rect outRect
  • View view
  • RecyclerView parent
  • RecyclerView.State state

这四个参数分别干什么的呢?我们不妨在 AndroidStudio 中按 Ctrl 键点击方法名,就可以到了它被调用的位置。

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 (
  • 61
    点赞
  • 166
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 27
    评论
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

frank909

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值