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

Android自定义标尺滑动选择值效果

程序员文章站 2022-06-29 09:16:45
本文实例为大家分享了android实现滑动标尺选择值,效果图 1.自定义属性attrs.xml

本文实例为大家分享了android实现滑动标尺选择值,效果图

Android自定义标尺滑动选择值效果

1.自定义属性attrs.xml

<declare-styleable name="rulerview">
    <attr name="textcolor" format="color" />
    <attr name="textsize" format="dimension" />
    <attr name="linecolor" format="color" />
    <attr name="linespacewidth" format="dimension" />
    <attr name="linewidth" format="dimension" />
    <attr name="linemaxheight" format="dimension" />
    <attr name="linemidheight" format="dimension" />
    <attr name="lineminheight" format="dimension" />
    <attr name="textmargintop" format="dimension" />
    <attr name="alphaenable" format="boolean" />
    <attr name="minvalue" format="float"/>
    <attr name="maxvalue" format="float"/>
    <attr name="selectorvalue" format="float"/>
    <attr name="pervalue" format="float"/>
</declare-styleable>

2.自定义rulerview

import android.content.context;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.util.attributeset;
import android.view.motionevent;
import android.view.velocitytracker;
import android.view.view;
import android.view.viewconfiguration;
import android.widget.scroller;


public class rulerview extends view {

  private int mminvelocity;
  private scroller mscroller; //scroller是一个专门用于处理滚动效果的工具类  用mscroller记录/计算view滚动的位置,再重写view的computescroll(),完成实际的滚动
  private velocitytracker mvelocitytracker; //主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。
  private int mwidth;
  private int mheight;

  private float mselectorvalue = 50.0f; // 未选择时 默认的值 滑动后表示当前中间指针正在指着的值
  private float mmaxvalue = 200;    // 最大数值
  private float mminvalue = 100.0f;   //最小的数值
  private float mpervalue = 1;     //最小单位 如 1:表示 每2条刻度差为1.  0.1:表示 每2条刻度差为0.1
  // 在demo中 身高mpervalue为1 体重mpervalue 为0.1

  private float mlinespacewidth = 5;  // 尺子刻度2条线之间的距离
  private float mlinewidth = 4;     // 尺子刻度的宽度

  private float mlinemaxheight = 420;  // 尺子刻度分为3中不同的高度。 mlinemaxheight表示最长的那根(也就是 10的倍数时的高度)
  private float mlinemidheight = 30;  // mlinemidheight 表示中间的高度(也就是 5 15 25 等时的高度)
  private float mlineminheight = 17;  // mlineminheight 表示最短的那个高度(也就是 1 2 3 4 等时的高度)

  private float mtextmargintop = 10;  //o
  private float mtextsize = 30;     //尺子刻度下方数字 textsize

  private boolean malphaenable = false; // 尺子 最左边 最后边是否需要透明 (透明效果更好点)

  private float mtextheight;      //尺子刻度下方数字 的高度

  private paint mtextpaint;       // 尺子刻度下方数字( 也就是每隔10个出现的数值) paint
  private paint mlinepaint;       // 尺子刻度 paint

  private int mtotalline;        //共有多少条 刻度
  private int mmaxoffset;        //所有刻度 共有多长
  private float moffset;        // 默认状态下,mselectorvalue所在的位置 位于尺子总刻度的位置
  private int mlastx, mmove;
  private onvaluechangelistener mlistener; // 滑动后数值回调

  private int mlinecolor = color.gray;  //刻度的颜色
  private int mtextcolor = color.black;  //文字的颜色


  public rulerview(context context) {
    this(context, null);

  }

  public rulerview(context context, attributeset attrs) {
    this(context, attrs, 0);
  }

  public rulerview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    init(context, attrs);
  }

  protected void init(context context, attributeset attrs) {
    mscroller = new scroller(context);
    this.mlinespacewidth = myfloat(25.0f);
    this.mlinewidth = myfloat(2.0f);
    this.mlinemaxheight = myfloat(100.0f);
    this.mlinemidheight = myfloat(60.0f);
    this.mlineminheight = myfloat(40.0f);
    this.mtextheight = myfloat(40.0f);


    final typedarray typedarray = context.obtainstyledattributes(attrs,
        r.styleable.rulerview);

    malphaenable = typedarray.getboolean(r.styleable.rulerview_alphaenable, malphaenable);

    mlinespacewidth = typedarray.getdimension(r.styleable.rulerview_linespacewidth, mlinespacewidth);
    mlinewidth = typedarray.getdimension(r.styleable.rulerview_linewidth, mlinewidth);
    mlinemaxheight = typedarray.getdimension(r.styleable.rulerview_linemaxheight, mlinemaxheight);
    mlinemidheight = typedarray.getdimension(r.styleable.rulerview_linemidheight, mlinemidheight);
    mlineminheight = typedarray.getdimension(r.styleable.rulerview_lineminheight, mlineminheight);
    mlinecolor = typedarray.getcolor(r.styleable.rulerview_linecolor, mlinecolor);

    mtextsize = typedarray.getdimension(r.styleable.rulerview_textsize, mtextsize);
    mtextcolor = typedarray.getcolor(r.styleable.rulerview_textcolor, mtextcolor);
    mtextmargintop = typedarray.getdimension(r.styleable.rulerview_textmargintop, mtextmargintop);

    mselectorvalue = typedarray.getfloat(r.styleable.rulerview_selectorvalue, 0.0f);
    mminvalue = typedarray.getfloat(r.styleable.rulerview_minvalue, 0.0f);
    mmaxvalue = typedarray.getfloat(r.styleable.rulerview_maxvalue, 100.0f);
    mpervalue = typedarray.getfloat(r.styleable.rulerview_pervalue, 0.1f);


    mminvelocity = viewconfiguration.get(getcontext()).getscaledminimumflingvelocity();

    mtextpaint = new paint(paint.anti_alias_flag);
    mtextpaint.settextsize(mtextsize);
    mtextpaint.setcolor(mtextcolor);
    mtextheight = getfontheight(mtextpaint);

    mlinepaint = new paint(paint.anti_alias_flag);
    mlinepaint.setstrokewidth(mlinewidth);
    mlinepaint.setcolor(mlinecolor);


    // setvalue(1990, 1940, 2016, 1);

  }


  public static int myfloat(float paramfloat) {
    return (int) (0.5f + paramfloat * 1.0f);
  }

  private float getfontheight(paint paint) {
    paint.fontmetrics fm = paint.getfontmetrics();
    return fm.descent - fm.ascent;
  }


  /**
   * @param selectorvalue 未选择时 默认的值 滑动后表示当前中间指针正在指着的值
   * @param minvalue   最大数值
   * @param maxvalue   最小的数值
   * @param per      最小单位 如 1:表示 每2条刻度差为1.  0.1:表示 每2条刻度差为0.1 在demo中 身高mpervalue为1 体重mpervalue 为0.1
   */
  public void setvalue(float selectorvalue, float minvalue, float maxvalue, float per) {
    this.mselectorvalue = selectorvalue;
    this.mmaxvalue = maxvalue;
    this.mminvalue = minvalue;
    this.mpervalue = (int) (per * 10.0f);
    this.mtotalline = ((int) ((mmaxvalue * 10 - mminvalue * 10) / mpervalue)) + 1;


    mmaxoffset = (int) (-(mtotalline - 1) * mlinespacewidth);
    moffset = (mminvalue - mselectorvalue) / mpervalue * mlinespacewidth * 10;
    invalidate();
    setvisibility(visible);
  }

  public void setonvaluechangelistener(onvaluechangelistener listener) {
    mlistener = listener;
  }

  @override
  protected void onsizechanged(int w, int h, int oldw, int oldh) {

    super.onsizechanged(w, h, oldw, oldh);
    if (w > 0 && h > 0) {
      mwidth = w;
      mheight = h;
    }
  }

  @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);

    float left, height;
    string value;
    int alpha = 0;
    float scale;
    int srcpointx = mwidth / 2;
    for (int i = 0; i < mtotalline; i++) {
      left = srcpointx + moffset + i * mlinespacewidth;

      if (left < 0 || left > mwidth) {
        continue; // 先画默认值在正中间,左右各一半的view。 多余部分暂时不画(也就是从默认值在中间,画旁边左右的刻度线)
      }

      /*文字*/
      if (i % 10 == 0) {
        value = string.valueof((int) (mminvalue + i * mpervalue / 10));
        if (malphaenable) {
          mtextpaint.setalpha(alpha);
        }
        canvas.drawtext(value, left - mtextpaint.measuretext(value) / 2,
            mtextheight, mtextpaint);  // 在为整数时,画 数值
      }

      /*线条*/
      if (i % 10 == 0) {
        height = mlineminheight;
      } else if (i % 5 == 0) {
        height = mlinemidheight;
      } else {
        height = mlinemaxheight;
      }
      if (malphaenable) {
        scale = 1 - math.abs(left - srcpointx) / srcpointx;
        alpha = (int) (255 * scale * scale);

        mlinepaint.setalpha(alpha);
      }
      canvas.drawline(left, mlinemaxheight + mtextmargintop + mtextheight, left, height, mlinepaint);

    }
  }

  @override
  public boolean ontouchevent(motionevent event) {
    int action = event.getaction();
    int xposition = (int) event.getx();

    if (mvelocitytracker == null) {
      mvelocitytracker = velocitytracker.obtain();
    }
    mvelocitytracker.addmovement(event);

    switch (action) {
      case motionevent.action_down:
        mscroller.forcefinished(true);
        mlastx = xposition;
        mmove = 0;
        break;
      case motionevent.action_move:
        mmove = (mlastx - xposition);
        changemoveandvalue();
        break;
      case motionevent.action_up:
      case motionevent.action_cancel:
        countmoveend();
        countvelocitytracker();
        return false;
      default:
        break;
    }

    mlastx = xposition;
    return true;
  }

  private void countvelocitytracker() {
    mvelocitytracker.computecurrentvelocity(1000); //初始化速率的单位
    float xvelocity = mvelocitytracker.getxvelocity(); //当前的速度
    if (math.abs(xvelocity) > mminvelocity) {
      mscroller.fling(0, 0, (int) xvelocity, 0, integer.min_value, integer.max_value, 0, 0);
    }
  }


  /**
   * 滑动结束后,若是指针在2条刻度之间时,改变moffset 让指针正好在刻度上。
   */
  private void countmoveend() {

    moffset -= mmove;
    if (moffset <= mmaxoffset) {
      moffset = mmaxoffset;
    } else if (moffset >= 0) {
      moffset = 0;
    }

    mlastx = 0;
    mmove = 0;

    mselectorvalue = mminvalue + math.round(math.abs(moffset) * 1.0f / mlinespacewidth) * mpervalue / 10.0f;
    moffset = (mminvalue - mselectorvalue) * 10.0f / mpervalue * mlinespacewidth;


    notifyvaluechange();
    postinvalidate();
  }


  /**
   * 滑动后的操作
   */
  private void changemoveandvalue() {
    moffset -= mmove;

    if (moffset <= mmaxoffset) {
      moffset = mmaxoffset;
      mmove = 0;
      mscroller.forcefinished(true);
    } else if (moffset >= 0) {
      moffset = 0;
      mmove = 0;
      mscroller.forcefinished(true);
    }
    mselectorvalue = mminvalue + math.round(math.abs(moffset) * 1.0f / mlinespacewidth) * mpervalue / 10.0f;


    notifyvaluechange();
    postinvalidate();
  }

  private void notifyvaluechange() {
    if (null != mlistener) {
      mlistener.onvaluechange(mselectorvalue);
    }
  }


  /**
   * 滑动后的回调
   */
  public interface onvaluechangelistener {
    void onvaluechange(float value);
  }

  @override
  public void computescroll() {
    super.computescroll();
    if (mscroller.computescrolloffset()) {   //mscroller.computescrolloffset()返回 true表示滑动还没有结束
      if (mscroller.getcurrx() == mscroller.getfinalx()) {
        countmoveend();
      } else {
        int xposition = mscroller.getcurrx();
        mmove = (mlastx - xposition);
        changemoveandvalue();
        mlastx = xposition;
      }
    }
  }
}

3.xml中使用activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <linearlayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:visibility="visible">

    <textview
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:includefontpadding="false"
      android:maxheight="17.0sp"
      android:text="身高(cm)"
      android:textcolor="#cc222222"
      android:textsize="15.0sp" />

    <textview
      android:id="@+id/tv_info_height_value"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margintop="11.0dip"
      android:includefontpadding="false"
      android:maxheight="24.0sp"
      android:textcolor="#cc222222"
      android:textsize="24.0sp" />

    <relativelayout
      android:layout_width="fill_parent"
      android:layout_height="wrap_content">

      <com.demo.ruleview.rulerview
        android:id="@+id/ruler_height"
        android:layout_width="fill_parent"
        android:layout_height="68.0dip"
        android:layout_margintop="24.0dip"
        app:alphaenable="true"
        app:linecolor="@color/gray"
        app:linemaxheight="40dp"
        app:linemidheight="30dp"
        app:lineminheight="20dp"
        app:linespacewidth="10dp"
        app:linewidth="2dip"
        app:maxvalue="250.0"
        app:minvalue="80.0"
        app:pervalue="1"
        app:textcolor="@color/black" />

      <imageview
        android:layout_width="14.0dip"
        android:layout_height="46.0dip"
        android:layout_centerhorizontal="true"
        android:layout_margintop="40.0dip"
        android:scaletype="fitxy"
        android:src="@drawable/info_ruler" />
    </relativelayout>


    <button
      android:id="@+id/click"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_margintop="10dp"
      android:text="点击改变" />

  </linearlayout>
</linearlayout>

4.activity中使用mainactivity

public class mainactivity extends appcompatactivity {

  private int maxvalue = 250;
  private int minvalue = 80;

  private rulerview rulerheight;
  private textview tvheightvalue;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    rulerheight = (rulerview) findviewbyid(r.id.ruler_height);
    tvheightvalue = (textview) findviewbyid(r.id.tv_info_height_value);

    shownumint();

    findviewbyid(r.id.click).setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {

        shownumint();

      }
    });

    rulerheight.setonvaluechangelistener(new rulerview.onvaluechangelistener() {
      @override
      public void onvaluechange(float value) {
        tvheightvalue.settext(string.valueof(value));
      }
    });
  }

  private void shownumint() {
    random rand = new random();
    int value = rand.nextint(maxvalue - minvalue + 1) + minvalue;
    rulerheight.setvalue(value, minvalue, maxvalue, 1);
    tvheightvalue.settext(string.valueof(integer.valueof(value)));
  }
}

ps:可自行根据需要绘制线条和文字,上下选择文字位置。

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