Android使用RecyclerView实现水平滚动控件

作者:daisy 时间:2021-09-10 20:17:54 

前言

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

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

     (2) 计算滚动距离.

     (3) 高亮中心视图.

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

     (5) 停止时自动对齐.

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

效果

Android使用RecyclerView实现水平滚动控件

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

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

滑动效果

Android使用RecyclerView实现水平滚动控件

总结

好了,以上就是这篇文章的全部内容了,我们可以根据这些定制各式各样的滚动条了!希望这篇文章对大家能有所帮助。

标签:android,recyclerview,水平,滚动
0
投稿

猜你喜欢

  • C# WinForm窗体编程中处理数字的正确操作方法

    2022-11-21 04:57:10
  • unity通过Mesh网格绘制图形(三角形、正方体、圆柱)

    2021-09-27 23:16:12
  • C# winform登陆框验证码的实现方法

    2022-08-26 12:45:58
  • 解决本机安装的JDK8,启动IDEA2019没反应的问题(开发工具)

    2023-08-12 23:29:11
  • Rxjava功能操作符的使用方法详解

    2021-06-10 06:57:16
  • C#中is和as用法实例分析

    2023-08-17 06:21:42
  • Spring Security账户与密码验证实现过程

    2023-03-04 21:54:37
  • Linux环境g++编译GDAL动态库操作方法

    2022-02-23 09:41:45
  • android获取ibeacon列表的方法

    2023-01-18 00:57:54
  • Android编程实现仿优酷旋转菜单效果(附demo源码)

    2022-03-06 11:25:32
  • java实现双色球机选号码生成器

    2022-10-05 07:41:33
  • 微信小程序 navigator 跳转url传递参数

    2022-03-17 05:46:56
  • Android动态加载布局实现技巧介绍

    2022-03-06 13:31:48
  • Java 集合中的类关于线程安全

    2023-03-13 12:53:22
  • DevExpress实现禁用TreeListNode CheckBox的方法

    2022-07-20 22:17:43
  • C#算法设计与分析详解

    2023-03-03 10:15:06
  • SpringBoot创建maven多模块项目实战代码

    2023-11-11 04:05:32
  • Android Camera开发实现可复用的相机组件

    2023-04-08 20:34:56
  • Visual Studio 2022 安装低版本 .Net Framework的图文教程

    2023-06-22 19:18:44
  • Android获取经纬度计算距离介绍

    2022-04-30 20:00:04
  • asp之家 软件编程 m.aspxhome.com