Android RecyclerView 实现横向滚动效果

本文介绍了一种使用RecyclerView实现的年龄滚动控件。通过水平布局、适配器定制及滚动逻辑,确保了滚动平滑、数据实时更新及停止时自动对齐等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

         滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点: 
(1) 对齐控件中心位置. 
(2) 计算滚动距离. 
(3) 高亮中心视图. 
(4) 实时显示中心数据. 
(5) 停止时自动对齐. 
(6) 滚动时, 设置按钮状态开关

免费源码

类似源码下载:  点击下载源码            点击下载源码2     github下载地址

 

1.RecyclerView部分逻辑:

 

 

  /**
     * 初始化年龄滑动条
     */
    private void initAgeList() {
        LinearLayoutManager mLayoutManager =
                new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
        mRvAgeList.setLayoutManager(mLayoutManager);
        mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
        mRvAgeList.setAdapter(mAgeAdapter);
        mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                mBDownStep.setEnabled(false);

                // 效果在暂停时显示, 否则会导致重绘异常
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    mAgeAdapter.highlightItem(getMiddlePosition());
                    mRvAgeList.scrollToPosition(getScrollPosition());
                    mLastValue = getMiddlePosition();
                    UserInfoManager.setAge(getMiddlePosition() + START_NUM);

                    mBDownStep.setEnabled(true); // 滑动时不可用, 停止时才可以
                }
            }

            @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                // 值是实时增加
                mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
            }
        });

        mAgeAdapter.highlightItem(getMiddlePosition());
    }/**
     * 初始化年龄滑动条
     */
    private void initAgeList() {
        LinearLayoutManager mLayoutManager =
                new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
        mRvAgeList.setLayoutManager(mLayoutManager);
        mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
        mRvAgeList.setAdapter(mAgeAdapter);
        mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                mBDownStep.setEnabled(false);

                // 效果在暂停时显示, 否则会导致重绘异常
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    mAgeAdapter.highlightItem(getMiddlePosition());
                    mRvAgeList.scrollToPosition(getScrollPosition());
                    mLastValue = getMiddlePosition();
                    UserInfoManager.setAge(getMiddlePosition() + START_NUM);

                    mBDownStep.setEnabled(true); // 滑动时不可用, 停止时才可以
                }
            }

            @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                // 值是实时增加
                mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
            }
        });

        mAgeAdapter.highlightItem(getMiddlePosition());
    }


 1).设置一个水平布局:

 

 

 

 

LinearLayoutManager mLayoutManager =
                new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
        mRvAgeList.setLayoutManager(mLayoutManager);


 2).添加Adapter, 设置起始和结束位置:

 

 

  mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
        mRvAgeList.setAdapter(mAgeAdapter); mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
        mRvAgeList.setAdapter(mAgeAdapter);


2.Adapter:

 

Adapter定制一些功能, 如标示指向中心位置, 数据联动显示, 高亮Item等

 

/**
 * 年龄的适配器
 * <p>
 * Created by wangchenlong on 15/11/12.
 */
public class PersonAgeAdapter extends RecyclerView.Adapter<PersonAgeAdapter.AgeItemViewHolder> {

    public static final int ITEM_NUM = 7; // 每行拥有的Item数, 必须是奇数

    private int mFrom; // 起始
    private int mTo; // 终止
    private int mHighlight = -1; // 高亮

    public PersonAgeAdapter(int from, int to) {
        mFrom = from;
        mTo = to;
    }

    @Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(parent.getContext()).
                inflate(R.layout.view_age_item, parent, false);

        // 设置Item的宽度
        ViewGroup.LayoutParams lp = item.getLayoutParams();
        lp.width = getItemStdWidth();

        return new AgeItemViewHolder(item);
    }

    @Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
        holder.getTextView().setText(String.valueOf(mFrom + position));

        // 高亮显示
        if (isSelected(position)) {
            holder.getTextView().setTextSize(30);
            holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
        } else {
            holder.getTextView().setTextSize(20);
            holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
        }
    }

    // 高亮中心, 更新前后位置
    public void highlightItem(int position) {
        mHighlight = position;
        int offset = ITEM_NUM / 2;
        for (int i = position - offset; i <= position + offset; ++i)
            notifyItemChanged(i);
    }

    // 判断是否是高亮
    public boolean isSelected(int position) {
        return mHighlight == position;
    }


    @Override public int getItemCount() {
        return mTo - mFrom + 1;
    }

    // 获取标准宽度
    public static int getItemStdWidth() {
        DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
        return displayMetrics.widthPixels / ITEM_NUM;
    }

    // ViewHolder
    public class AgeItemViewHolder extends RecyclerView.ViewHolder {

        private TextView mTextView;

        public AgeItemViewHolder(View itemView) {
            super(itemView);

            mTextView = (TextView) itemView.findViewById(R.id.item_age_value);
            mTextView.setTag(this);
        }

        public TextView getTextView() {
            return mTextView;
        }
    }
}


每个单元格宽度是屏幕宽度的奇数分之一, 填充屏幕, 则起始指向中心

 

 

 

 

 @Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(parent.getContext()).
                inflate(R.layout.view_age_item, parent, false);

        // 设置Item的宽度
        ViewGroup.LayoutParams lp = item.getLayoutParams();
        lp.width = getItemStdWidth();

        return new AgeItemViewHolder(item);
    }

 

 

单数Item数量, 则中心的指示器必指向中心Item的中心,根据选中状态, 更新Item样式.

 

 

  @Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
        holder.getTextView().setText(String.valueOf(mFrom + position));

        // 高亮显示
        if (isSelected(position)) {
            holder.getTextView().setTextSize(30);
            holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
        } else {
            holder.getTextView().setTextSize(20);
            holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
        }
    }


设置高亮, 把中心位置高亮, 两边恢复, 通知Adapter重绘ViewHolder

 

 

 

 

 

  // 高亮中心, 更新前后位置
    public void highlightItem(int position) {
        mHighlight = position;
        int offset = ITEM_NUM / 2;
        for (int i = position - offset; i <= position + offset; ++i)
            notifyItemChanged(i);
    }

    // 判断是否是高亮
    public boolean isSelected(int position) {
        return mHighlight == position;
    }

 

 

notifyItemChanged()会重绘所选择的页面,获取宽度, 把一行显示Item数量设置为单数, 则中心指向一个Item

 

 

 // 获取标准宽度
    public static int getItemStdWidth() {
        DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
        return displayMetrics.widthPixels / ITEM_NUM;
    }

 

 

注意RecyclerView不能移动半个单元, 每行数量是单数时, 则必会指向中心


3.滚动逻辑

在滚动时, 实时更新页面显示; 在停止时, 更新高亮和存储数据; 滚动结束时, 激活按钮

 

 

  mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                mBDownStep.setEnabled(false);

                // 效果在暂停时显示, 否则会导致重绘异常
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    mAgeAdapter.highlightItem(getMiddlePosition());
                    mRvAgeList.scrollToPosition(getScrollPosition());
                    mLastValue = getMiddlePosition();
                    UserInfoManager.setAge(getMiddlePosition() + START_NUM);

                    mBDownStep.setEnabled(true); // 滑动时不可用, 停止时才可以
                }
            }

            @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                // 值是实时增加
                mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
            }
        });

        mAgeAdapter.highlightItem(getMiddlePosition());
    }

    /**
     * 获取中间位置
     *
     * @return 当前值
     */
    private int getMiddlePosition() {
        return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
    }

    /**
     * 获取滑动值, 滑动偏移 / 每个格子宽度
     *
     * @return 当前值
     */
    private int getScrollPosition() {
        return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
                / (double) PersonAgeAdapter.getItemStdWidth());
    }


判断滚动的距离单位, 偏移总距离/单个Item宽度

 

 

 private int getScrollPosition() {
        return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
                / (double) PersonAgeAdapter.getItemStdWidth());
    }

 

 

 

 

 

 

computeHorizontalScrollOffset()获取RecyclerView的偏移总位移


中间位置, 还要加上半行Item数量

 

 

 

 

 

private int getMiddlePosition() {
        return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
    }


判断滚动是否停止

 

 

 

 

if (newState == RecyclerView.SCROLL_STATE_IDLE)

 

 

在滚动停止时, 自动对齐

 

mRvAgeList.scrollToPosition(getScrollPosition());


调用需要高亮显示的Item

 

 

<span style="color:#333333">mAgeAdapter.highlightItem(getMiddlePosition());</span>

 

 

注意在滚动停止时, 更新高亮比较好, 否则重绘速度较慢, 会影响滚动效果

 

 

 

 

 

 

 
 
OK
 

 

其它:

https://blog.youkuaiyun.com/Blog_Sun/article/details/95338124

 

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值