使用RecyclerView实现滚动控件

滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点:

(1) 对齐控件中心位置.

(2) 计算滚动距离.

(3) 高亮中心视图.

(4) 实时显示中心数据.

(5) 停止时自动对齐.

(6) 滚动时, 设置按钮状态开关.

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());
    }

设置一个水平布局

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

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

        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.

mAgeAdapter.highlightItem(getMiddlePosition());

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

推荐, 介绍RecyclerView的文章, 特别详细.

OK, 我们可以根据这些定制各式各样的滚动条了!

时间: 2024-10-15 13:56:22

使用RecyclerView实现滚动控件的相关文章

RecyclerView(滚动控件)的用法

1.首先在build.gradle中添加依赖库 compile 'com.android.support:recyclerview-v7:24.2.1' 2.修改activity_main.xml <LinearLayout ...... <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="maych_parent" a

Android实现图片滚动控件

怎样实现图片滚动器的效果. 今天就总结下.这里我也不多说什么.直接源代码.不懂的直接提问我. 第一种实现方式:利用Gallery,但是这个现在已经过时了.我这里不多介绍了.只贴一个核心类. package com.drocode.swithcer; import java.util.TimerTask; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import

Recyclerview点击事件,更新item的UI+更新Recyclerview外的控件

项目中用到了Recyclerview,在第一行代码中学到了一种相对来说简单的点击事件方法,可是这种点击事件是在adapter中写的,没有教怎么更新item的ui和更新Recyclerview之外的控件,研究了一下,写下我的方案. 需求如下图: 首先设置点击事件,在ViewHolder中添加View view变量来保存item最外层布局的实例. 然后在onCreateViewHolder()中注册点击事件,可以为item设置点击事件,也可以为item中的控件eg:TextView设置点击事件.这正

Android高级图片滚动控件,编写3D版的图片轮播器

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482089 大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博客了,我也是深感惭愧.那么今天的这篇既然是阔别了一个多月的文章,当然要带来更加给力点的内容了,那么话不多说,赶快进入到今天的正题吧. 说 到图片轮播器,很多的Android应用中都会带有这个功能,比如说网易新闻.淘宝等.最新我们公司的一款应用也加入了这个功能,并且在图片轮播的基础上 还增加了三维立体

[android] 手机卫士自定义滚动控件

TextView控件设置单行显示 android:singleLine=”true” 设置TextView开始的位置显示省略号,android:ellipsize=”start” 设置滚动属性,android:ellipsize=”marquee” 当控件有焦点的时候,才会调用那个滚动效果 新建一个ui包 新建一个类FocusedTextView继承系统的TextView 重写构造方法 重写isFoused()方法,返回true,就可以让它生来就有焦点,其实并没有焦点,只是欺骗了android系

IOS ScrollView滚动控件使用

1.ScrollView概述: ScrollView是UIScrollView类,是容器类型的视图. 它有两个子类: UITextView和UITableView,它们在内容超出屏幕时提供水平或垂直滚动条. 2.其包含3个属性: contentSize:表示SCrollView中的内容视图 contentInset:用于在ScrollView中的内容视图周边添加边框,这往往为了留出空白以放置工具栏.标签或导航栏等 contentOffset:内容视图坐标原点与ScrollVIew坐标原点的偏移量

HorizontalScrollView水平滚动控件

一.HorizontalScrollView控件只是支持水平滚动,而且它只能包含一个控件,通常是在< HorizontalScrollView >标签中定义了一个<LinearLayout> 标签并且在<LinearLayout>标签中android:orientation属性值设置为horizontal,然后在<LinearLayout>标签中放置多个控件,如果<LinearLayout>标签中的控件所占用的总宽度超出屏幕的宽度,就会出现滚动效

ScrollView垂直滚动控件的使用

一.ScrollView控件只是支持垂直滚动,而且在ScrollView中只能包含一个控件,通常是在< ScrollView >标签中定义了一个<LinearLayout> 标签并且在<LinearLayout>标签中android:orientation属性值设置为vertical,然后在<LinearLayout>标签中放置多个控件,如果<LinearLayout>标签中的控件所占用的总高度超出屏幕的高度,就会在屏幕的右侧出现一个滚动条. 在

Android文字跑马灯控件(文本自动滚动控件)

最近在开发一个应用,需要用到文本的跑马灯效果,图省事,在网上找,但老半天都找不到,后来自己写了一个,很简单,代码如下: import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; impor