当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义标尺滑动选择值效果

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

2019年08月02日  | 移动技术网IT编程  | 我要评论

邵东政府网,小丁猫,宣城十八巷论坛

本文实例为大家分享了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:可自行根据需要绘制线条和文字,上下选择文字位置。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网