RecyclerView之ItemDecoration详解(上)

转载请注明出处:http://blog.csdn.net/binbinqq86/article/details/54090829

RecyclerView的出现让许多人眼前一亮,当然在整个开发者圈子里面也拥有很不错的口碑,相比ListView而言,它高度灵活的使用方式也让很多新手感到不知所措,虽然做Android开发也有些时间了,但也是最近才转到RecyclerView上,不用不知道,一用就发现它真的很强大,比如传统的ListView和GridView所有的功能和效果它都能轻松实现,而最新的嵌套滑动它也能够很完美的支持,复杂的瀑布流效果对它而言就是小菜一碟,还有各种炫酷的item动画,总之只要你能够想到的就没有它实现不了的。

本文主要对RecyclerView中的ItemDecoration进行一个详细的讲解,虽然网上也有很多类似的文章,但想要真正理解关于这个抽象类的使用,具体每个方法和参数的含义是什么,怎么去实现一个自己想要的divider的时候,却发现其实不是那么容易,仍然需要自己去进行实践和整理,于是我就把自己所研究和理解的东西做一个相关的记录,同时也分享给大家。

首先贴上官方的解释:

An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter's data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.

All ItemDecorations are drawn in the order they were added, before the item views (in onDraw() and after the items (in onDrawOver(Canvas, RecyclerView, RecyclerView.State).

大致意思就是ItemDecoration允许应用去添加一个特殊的图形,并且布局在item的偏移处,这样就可以在item之间显示分割线。所有的分割线都被按照添加的顺序去绘制,onDraw是绘制在item的后面,而onDrawOver则是绘制在最上层。

当然官方也提供了一个默认的子类——android.support.v7.widget.DividerItemDecoration
这个类很简单,下面是代码:

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.support.v7.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.widget.LinearLayout;

/**
 * DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider
 * between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and
 * {@link #VERTICAL} orientations.
 *
 * <pre>
 *     mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
 *             mLayoutManager.getOrientation());
 *     recyclerView.addItemDecoration(mDividerItemDecoration);
 * </pre>
 */
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
   
    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
    public st
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerView 是 Android 中一个强大的视图组件,它可以用于显示大量的数据,同时还支持循环滚动,也就是说当滚动到数据的末尾时,它可以自动回到数据的开头,实现循环滚动的效果。下面我将详细介绍 RecyclerView 如何实现循环滚动。 1. 使用无限循环的数据源 循环滚动的关键在于数据源,我们需要使用一个无限循环的数据源来实现循环滚动的效果。具体实现方式如下: ``` public class InfiniteAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<YourData> mDataList; public InfiniteAdapter(List<YourData> dataList) { mDataList = new ArrayList<>(); mDataList.addAll(dataList); mDataList.addAll(dataList); mDataList.addAll(dataList); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // 创建 ViewHolder } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { // 绑定数据到 ViewHolder } @Override public int getItemCount() { return Integer.MAX_VALUE; } public YourData getData(int position) { return mDataList.get(position % mDataList.size()); } } ``` 在上面的代码中,我们通过将原始数据源复制三次来实现了无限循环的数据源。同时,getItemCount() 方法返回了一个很大的数值,使得 RecyclerView 认为数据源有无限多的数据。在 onBindViewHolder() 方法中,我们通过 getData() 方法获取对应位置的数据,这个方法会将位置对 mDataList 的大小取模,从而实现了循环滚动的效果。 2. 使用自定义的 LayoutManager RecyclerView 的 LayoutManager 负责决定子视图的排布位置,我们可以通过自定义 LayoutManager 来实现循环滚动的效果。下面是一个简单的自定义 LinearLayoutManager: ``` public class LoopLayoutManager extends LinearLayoutManager { public LoopLayoutManager(Context context) { super(context); } @Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { int scrolled = super.scrollVerticallyBy(dy, recycler, state); int firstVisibleItemPosition = findFirstVisibleItemPosition(); int lastVisibleItemPosition = findLastVisibleItemPosition(); int itemCount = state.getItemCount(); if (scrolled != 0 && firstVisibleItemPosition == 0 && lastVisibleItemPosition == itemCount - 1) { // 如果滚动了且第一个可见视图是第一个元素,同时最后一个可见视图是最后一个元素,说明已经滚到底部 // 这时需要将屏幕上的最后一个元素移动到屏幕顶部,实现循环滚动的效果 View lastView = findViewByPosition(lastVisibleItemPosition); int offset = getHeight() - getDecoratedBottom(lastView); if (offset > 0) { scrolled -= offset; offsetChildrenVertical(-offset); } } return scrolled; } } ``` 在上面的代码中,我们重写了 scrollVerticallyBy() 方法,当滚动到底部时,将屏幕上的最后一个元素移动到屏幕顶部,从而实现了循环滚动的效果。 3. 设置边界回调 还有一种实现循环滚动的方式是通过设置边界回调来实现。具体实现方式如下: ``` public class LoopCallback extends RecyclerView.ItemDecoration { private int mSpace; public LoopCallback(int space) { mSpace = space; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); int itemCount = state.getItemCount(); if (position == 0) { // 如果是第一个元素,需要在顶部添加一个元素作为循环滚动的结束标志 outRect.top = mSpace; outRect.bottom = 0; } else if (position == itemCount - 1) { // 如果是最后一个元素,需要在底部添加一个元素作为循环滚动的结束标志 outRect.top = 0; outRect.bottom = mSpace; } else { outRect.top = 0; outRect.bottom = 0; } } } ``` 在上面的代码中,我们通过设置 ItemDecoration 来控制各个元素之间的间距,并且在第一个元素的顶部和最后一个元素的底部添加了一个元素作为循环滚动的结束标志。同时,我们需要在 RecyclerView 中设置一个边界回调,当滚动到边界时,就会调用这个回调并且触发循环滚动。具体实现方式如下: ``` mRecyclerView.addItemDecoration(new LoopCallback(20)); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition(); int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); int itemCount = recyclerView.getAdapter().getItemCount(); if (firstVisibleItemPosition == 0) { // 如果第一个可见元素是第一个元素,说明已经滚到了顶部 // 这时需要将屏幕上的第一个元素移动到屏幕底部,实现循环滚动的效果 recyclerView.smoothScrollBy(0, recyclerView.getHeight()); } else if (lastVisibleItemPosition == itemCount - 1) { // 如果最后一个可见元素是最后一个元素,说明已经滚到了底部 // 这时需要将屏幕上的最后一个元素移动到屏幕顶部,实现循环滚动的效果 recyclerView.smoothScrollBy(0, -recyclerView.getHeight()); } } } } }); ``` 在上面的代码中,我们通过监听 RecyclerView 的滚动状态来判断是否滚到了边界,并且调用 smoothScrollBy() 方法将屏幕上的第一个元素移动到屏幕底部或者将屏幕上的最后一个元素移动到屏幕顶部,从而实现了循环滚动的效果。 综上所述,RecyclerView 实现循环滚动的方式有很多种,我们可以根据实际需求选择合适的方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值