欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-05 23:05:37
前言 相信大家都知道android滚动控件的实现方式有很多, 使用recyclerview也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看recyclerview...

前言

相信大家都知道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实现水平滚动控件

总结

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