Android自定义RecyclerView实现不固定刻度的刻度尺

2022-07-30,,,,

本文实例为大家分享了自定义recyclerview实现不固定刻度刻度尺的具体代码,供大家参考,具体内容如下

##不均匀刻度效果图

##等比例刻度效果图

实现功能目前

1、实现类似日期/分类等大小不固定的水平刻度尺效果
2、实现标准刻度尺效果
3、监听recyclerview滑动时居中条目
4、去掉边缘阴影

定义recyclerview

public class centerrecyclerview extends recyclerview {

//设置recyclerview的速度
 private static final int maximum_fling_velocity = 3000;
//画中轴线
 private paint mcenterlinepaint;
 private context context;
 private centerlayoutmanager mlayoutmanager;
 private paint mtextpaint;
 private string text = "";
 private string textunit = "";
 private paint mtextunitpaint;
 private int mwidth;
 private int mheight;
 private int mlinestarty;
 private int mlineendy;
 private int mtextstarty;

 public centerrecyclerview(@nonnull context context) {
  this(context, null);
 }

 public centerrecyclerview(@nonnull context context, @nullable attributeset attrs) {
  this(context, attrs, -1);
 }

 public centerrecyclerview(@nonnull context context, @nullable attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context, attrs);
 }

 private void init(context context, attributeset attrs) {
  this.context = context;
  initpaint();
 }

 public void settypeface(typeface typeface) {
  mtextpaint.settypeface(typeface);
  mtextunitpaint.settypeface(typeface);
 }

 private void initpaint() {
  mcenterlinepaint = new paint();
  mcenterlinepaint.setantialias(true);
  mcenterlinepaint.setstrokewidth(screenutil.dip2px(context, 4));
  mcenterlinepaint.settextalign(paint.align.center);
  mcenterlinepaint.setcolor(0xff6e9fff);

  mtextunitpaint = new paint();
  mtextunitpaint.setstyle(paint.style.fill);
  mtextunitpaint.setstrokewidth(screenutil.dip2px(context, 4));
  mtextunitpaint.settextsize(screenutil.dip2px(context, 15));
  mtextunitpaint.setcolor(color.parsecolor("#dd5f00"));

  mtextpaint = new paint();
  mtextpaint.setstyle(paint.style.fill);
  mtextpaint.setstrokewidth(screenutil.dip2px(context, 4));
  mtextpaint.settextsize(screenutil.dip2px(context, 60));
  mtextpaint.setcolor(color.parsecolor("#dd5f00"));
  mtextpaint.settextalign(paint.align.center);
 }

 @override
 public void addonscrolllistener(@nonnull onscrolllistener listener) {
  super.addonscrolllistener(listener);
  postinvalidate();
 }

 @override
 protected void onmeasure(int widthspec, int heightspec) {
  super.onmeasure(widthspec, heightspec);

 }

//获取相关参数
 @override
 protected void onlayout(boolean changed, int l, int t, int r, int b) {
  super.onlayout(changed, l, t, r, b);
  mwidth = getwidth();
  mheight = getheight();
  int lineheight = screenutil.dip2px(context, 58);
  mlinestarty = mheight / 2 - lineheight / 2;
  mlineendy = mheight / 2 + lineheight / 2;
  mtextstarty = mheight / 2 - screenutil.dip2px(context, 55);
 }

 @override
 public void draw(canvas c) {
  super.draw(c);
  log.d("szjjyh", "draw: " + getwidth());
  drawcenterline(c);
  drawtext(c);
 }

//画线
 private void drawcenterline(canvas canvas) {
  canvas.drawline(mwidth / 2, mlinestarty, mwidth / 2, mlineendy, mcenterlinepaint);
 }

//画字/画单位
 private void drawtext(canvas c) {
  c.drawtext(text, mwidth / 2, mtextstarty, mtextpaint);
  if (textunit != null && textunit.length() != 0) {
   float textwidth = mtextpaint.measuretext(text);
   c.drawtext(textunit, (mwidth + textwidth) / 2, mtextstarty, mtextunitpaint);
  }
 }

 public string gettext() {
  return text;
 }

 public void settext(string text) {
  if (text == null) {
   return;
  }
  this.text = text;
 }

 public string gettextunit() {
  return textunit;
 }

 public void settextunit(string textunit) {
  if (textunit == null) {
   return;
  }
  this.textunit = textunit;
 }

 @override
 public void setadapter(@nullable adapter adapter) {
  super.setadapter(adapter);
 }

 @override
 public void setlayoutmanager(@nullable layoutmanager layout) {
  super.setlayoutmanager(layout);
  mlayoutmanager = (centerlayoutmanager) layout;
 }

 @override
 public boolean fling(int velocityx, int velocityy) {
  velocityx = solvevelocity(velocityx);
  velocityy = solvevelocity(velocityy);
  return super.fling(velocityx, velocityy);
 }

 private int solvevelocity(int velocity) {
  if (velocity > 0) {
   return math.min(velocity, maximum_fling_velocity);
  } else {
   return math.max(velocity, -maximum_fling_velocity);
  }
 }

// @override
// protected float getleftfadingedgestrength() {
//  return 0;
// }
}

定义linearlayoutmanager

public class centerlayoutmanager extends linearlayoutmanager {
 public centerlayoutmanager(context context) {
  super(context);
 }

 public centerlayoutmanager(context context, int orientation, boolean reverselayout) {
  super(context, orientation, reverselayout);
 }

 public centerlayoutmanager(context context, attributeset attrs, int defstyleattr, int defstyleres) {
  super(context, attrs, defstyleattr, defstyleres);
 }
//计算偏移量自己适配
 @override
 public void scrolltoposition(int position) {
  scrolltopositionwithoffset(position,-15);
 }

 @override
 public void scrolltopositionwithoffset(int position, int offset) {
  super.scrolltopositionwithoffset(position, offset);
 }
 @override
 public void smoothscrolltoposition(recyclerview recyclerview, recyclerview.state state, int position) {
  recyclerview.smoothscroller smoothscroller = new centersmoothscroller(recyclerview.getcontext());
  smoothscroller.settargetposition(position);
  startsmoothscroll(smoothscroller);
 }

 public void smoothscrolltoposition(recyclerview recyclerview, int position) {
  recyclerview.smoothscroller smoothscroller = new centersmoothscroller(recyclerview.getcontext());
  smoothscroller.settargetposition(position);
  startsmoothscroll(smoothscroller);
 }


 private static class centersmoothscroller extends linearsmoothscroller {

  centersmoothscroller(context context) {
   super(context);
  }

//滑动到中间位置
  @override
  public int calculatedttofit(int viewstart, int viewend, int boxstart, int boxend, int snappreference) {
   return (boxstart + (boxend - boxstart) / 2) - (viewstart + (viewend - viewstart) / 2);
  }
//滚动速度设置
  @override
  protected float calculatespeedperpixel(displaymetrics displaymetrics) {
   return 4;
  }

  @override
  protected int getverticalsnappreference() {
   return super.getverticalsnappreference();
  }
 }
 
}

滑动事件监听

public class centerscrolllistener extends recyclerview.onscrolllistener {

 private centerlayoutmanager mlayoutmanager;
 recyclerview recyclerview;
 private int mposition;
 private double intscrollstate;
 private int mfirstitemposition1;
 private int mlastitemposition1;
 private boolean is_stop;
 private string tag = "centerscrolllistener";
 private double is_playsound;

 public centerscrolllistener(onitemcenterscrollistner onitemcenterscrollistner) {
  this.onitemcenterscrollistner = onitemcenterscrollistner;
 }

 public void onscrollstatechanged(@nonnull recyclerview recyclerview, int newstate) {
  init(recyclerview);
  intscrollstate = newstate;
  is_stop = false;

  if (intscrollstate == recyclerview.scroll_state_idle) {
   log.e(tag, "onscrollstatechanged: 11111:"+mposition);
   ceterscroll(0, mposition);
  }
 }

 public void onscrolled(@nonnull recyclerview recyclerview, int dx, int dy) {
  init(recyclerview);
  int x = math.abs(dx);
  if (!is_stop && x <= 1) {
   is_stop = true;
   if (dx >= 0) {
    mposition = (mfirstitemposition1 + mlastitemposition1) / 2;
    view childat = mlayoutmanager.findviewbyposition(mposition);
    if (childat.getleft() < screenutil.getscreenwidth(recyclerview.getcontext()) / 2) {
     mposition = mposition + 1;
    }
    log.e(tag, "111111: w:" + childat.getwidth() + " :l:" +
      childat.getleft() + " :r:" + childat.getright());
   } else {
    mposition = (mfirstitemposition1 + mlastitemposition1) / 2;
    view childat = mlayoutmanager.findviewbyposition(mposition);
    if (childat.getleft() > screenutil.getscreenwidth(recyclerview.getcontext()) / 2) {
     mposition = mposition - 1;
    }
   }
  }
  ceterscroll(x, mposition);
 }

//事件监听
 private void init(@nonnull recyclerview recyclerview) {
  this.recyclerview = recyclerview;
  if (mlayoutmanager == null) {
   mlayoutmanager = (centerlayoutmanager) recyclerview.getlayoutmanager();
  }
  int firstitemposition = mlayoutmanager.findfirstvisibleitemposition();
  int lastitemposition = mlayoutmanager.findlastvisibleitemposition();
  mfirstitemposition1 = mlayoutmanager.findfirstcompletelyvisibleitemposition();
  mlastitemposition1 = mlayoutmanager.findlastcompletelyvisibleitemposition();
  mposition = (mfirstitemposition1 + mlastitemposition1) / 2;

  if (is_playsound != mposition) {
   is_playsound = mposition;
   int count = mlayoutmanager.getitemcount();
//     soundpool.play(soundmap.get(1), 1, 1, 0, 0, 1);
   if (onitemcenterscrollistner != null) {
//中间条目事件监听
    onitemcenterscrollistner.onitemcenterscrollistner(mlastitemposition1, mposition,count);
   }
  }

//目前由于要实现灰色条目当条目间距为10dp,屏幕宽度360时不能继续滑动
  if (mposition <= 18) {
   ceterscroll(0, 18);
  }
 }

//速度变小时自动滚动到中间位置
 private void ceterscroll(int dx, int position) {
  if ((intscrollstate == recyclerview.scroll_state_settling || intscrollstate
    == recyclerview.scroll_state_idle) && math.abs(dx) <= 1) {
   mlayoutmanager.smoothscrolltoposition(recyclerview, position);
  }
 }

 onitemcenterscrollistner onitemcenterscrollistner;

 public void setonitemcenterscrollistner(onitemcenterscrollistner onitemcenterscrollistner) {
  this.onitemcenterscrollistner = onitemcenterscrollistner;
 }

 public interface onitemcenterscrollistner {
  void onitemcenterscrollistner(int lastitemposition1, int position, int count);
 }

adpater实现

public class dateadapter extends baserecycleradapter<calendardatebean> {

 private static final int layoutid = r.layout.view_item_date;

 public dateadapter(context context, list<calendardatebean> datas) {
  super(context, datas, layoutid);
 }

 @override
 protected void binddata(baseviewholder holder, calendardatebean data, int position) {
  if (data.getday() == 1) {
//r.id.tv_1为线需要居中否则和中轴线不会完全对称 r.id.tv_2为大刻度文字
   holder.getview(r.id.tv_1).setscalex(2f);
   holder.settext(r.id.tv_2, data.getmonth() + "月");
   holder.getview(r.id.tv_2).setvisibility(view.visible);
   holder.getview(r.id.tv_1).setbackgroundcolor(color.parsecolor("#ffffff"));
  } else if (data.getday() ==-1){
   holder.getview(r.id.tv_1).setscalex(1f);
   holder.getview(r.id.tv_2).setvisibility(view.gone);
   holder.getview(r.id.tv_1).setbackgroundcolor(color.parsecolor("#222222"));
  }else {
   holder.getview(r.id.tv_1).setscalex(1f);
   holder.getview(r.id.tv_2).setvisibility(view.gone);
   holder.getview(r.id.tv_1).setbackgroundcolor(color.parsecolor("#ffffff"));
  }
 }
 
}

activity 加载view展示

private void initrecyclerview() {
//此处试配时注意item10dp 宽度360 计算发放 360/10/2得到记得适配
  for (int i = 0; i < 18; i++) {
   timebean timebean = new timebean();
   mlist.add(timebean);
  }
  for (int i = 0; i < 1440; i++) {
   int minute = i % 60;
   int hour = i / 60;
   if (calendarutil.gethourtime()==hour&&calendarutil.getminutetime()==minute){
    mpostion = i;
   }
   timebean timebean = new timebean();
   timebean.sethour(hour);
   timebean.setminute(minute);
   timebean.settimedate(calendarutil.gethourtominute(hour,minute));
   mlist.add(timebean);
  }
  for (int i = 0; i < 18; i++) {
   timebean timebean = new timebean();
//   timebean.setminute(-1);
   mlist.add(timebean);
  }

  rv_data = findviewbyid(r.id.rv_data);
  madapter = new timeadapter(this, mlist);
  rv_data.setadapter(madapter);
//设置字体
  rv_data.settypeface(typeface.createfromasset(getassets(), "fonts/dincond_boldalternate.ttf"));
  centerlayoutmanager layoutmanager = new centerlayoutmanager(this);
  layoutmanager.setorientation(linearlayoutmanager.horizontal);
  rv_data.setlayoutmanager(layoutmanager);

  rv_data.scrolltoposition(mpostion);
  rv_data.addonscrolllistener(new centerscrolllistener((lastitemposition, position,count) -> {
//更新文本和单位
   rv_data.settext(mlist.get(position).gettimedate());
   if (mlist.get(position).gethour()>12){
    rv_data.settextunit("pm");
   }else {
    rv_data.settextunit("am");
   }
  }));

 }

实现了基本代码全部写了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

《Android自定义RecyclerView实现不固定刻度的刻度尺.doc》

下载本文的Word格式文档,以方便收藏与打印。