返回

RecyclerView 可折叠的秘密

Android

简化 RecyclerView,开启折叠之旅

RecyclerView 有很高的自由度,可以说只有想不到没有做不到,真是越用越喜欢。这次用超简单的方法,让 RecyclerView 带上折叠的效果。效果是这样的。首项的差动。下面我们来一个个解决。我们新建一个 ParallaxRecyclerView,让它继承 RecyclerView。

首先,为 ParallaxRecyclerView 定义属性。这些属性将用于控制折叠效果的行为。

public class ParallaxRecyclerView extends RecyclerView {

    // 展开/折叠的阈值
    private float mThreshold;

    // 当前折叠的项目索引
    private int mCollapsedIndex;

    // 动画持续时间
    private long mAnimationDuration;

    public ParallaxRecyclerView(Context context) {
        super(context);
        init();
    }

    public ParallaxRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ParallaxRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        // 默认展开/折叠阈值为 100dp
        mThreshold = 100 * getResources().getDisplayMetrics().density;

        // 默认动画持续时间为 300ms
        mAnimationDuration = 300;
    }

    // 设置展开/折叠阈值
    public void setThreshold(float threshold) {
        mThreshold = threshold;
    }

    // 设置动画持续时间
    public void setAnimationDuration(long duration) {
        mAnimationDuration = duration;
    }

    // 展开/折叠项目
    public void toggleItem(int position) {
        // 如果当前项目已经折叠,则展开它
        if (mCollapsedIndex == position) {
            expandItem(position);
        } else {
            // 如果当前项目未折叠,则折叠它
            collapseItem(position);
        }
    }

    // 展开项目
    private void expandItem(int position) {
        // 获取要展开的项目视图
        View view = findViewHolderForAdapterPosition(position).itemView;

        // 创建一个动画,使视图从当前高度展开到完全展开
        ValueAnimator animator = ValueAnimator.ofInt(view.getHeight(), (int) mThreshold);
        animator.setDuration(mAnimationDuration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 设置视图的高度
                view.getLayoutParams().height = (int) animation.getAnimatedValue();
                view.requestLayout();
            }
        });
        animator.start();

        // 将当前折叠的项目索引设置为 -1,表示没有项目折叠
        mCollapsedIndex = -1;
    }

    // 折叠项目
    private void collapseItem(int position) {
        // 获取要折叠的项目视图
        View view = findViewHolderForAdapterPosition(position).itemView;

        // 创建一个动画,使视图从当前高度折叠到 0
        ValueAnimator animator = ValueAnimator.ofInt(view.getHeight(), 0);
        animator.setDuration(mAnimationDuration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 设置视图的高度
                view.getLayoutParams().height = (int) animation.getAnimatedValue();
                view.requestLayout();
            }
        });
        animator.start();

        // 将当前折叠的项目索引设置为要折叠的项目的索引
        mCollapsedIndex = position;
    }
}

然后,在需要折叠效果的列表项的布局文件中添加如下代码:

<androidx.recyclerview.widget.ParallaxRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

最后,在 Activity 或 Fragment 中获取 RecyclerView 并设置折叠效果的属性:

ParallaxRecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setThreshold(100 * getResources().getDisplayMetrics().density);
recyclerView.setAnimationDuration(300);

这样,您就可以为 RecyclerView 添加折叠效果了。