溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Android自定義標(biāo)尺滑動(dòng)選擇值效果

發(fā)布時(shí)間:2020-10-16 07:40:15 來(lái)源:腳本之家 閱讀:309 作者:676598624 欄目:移動(dòng)開(kāi)發(fā)

本文實(shí)例為大家分享了Android實(shí)現(xiàn)滑動(dòng)標(biāo)尺選擇值,效果圖

Android自定義標(biāo)尺滑動(dòng)選擇值效果

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是一個(gè)專(zhuān)門(mén)用于處理滾動(dòng)效果的工具類(lèi)  用mScroller記錄/計(jì)算View滾動(dòng)的位置,再重寫(xiě)View的computeScroll(),完成實(shí)際的滾動(dòng)
  private VelocityTracker mVelocityTracker; //主要用跟蹤觸摸屏事件(flinging事件和其他gestures手勢(shì)事件)的速率。
  private int mWidth;
  private int mHeight;

  private float mSelectorValue = 50.0f; // 未選擇時(shí) 默認(rèn)的值 滑動(dòng)后表示當(dāng)前中間指針正在指著的值
  private float mMaxValue = 200;    // 最大數(shù)值
  private float mMinValue = 100.0f;   //最小的數(shù)值
  private float mPerValue = 1;     //最小單位 如 1:表示 每2條刻度差為1.  0.1:表示 每2條刻度差為0.1
  // 在demo中 身高mPerValue為1 體重mPerValue 為0.1

  private float mLineSpaceWidth = 5;  // 尺子刻度2條線(xiàn)之間的距離
  private float mLineWidth = 4;     // 尺子刻度的寬度

  private float mLineMaxHeight = 420;  // 尺子刻度分為3中不同的高度。 mLineMaxHeight表示最長(zhǎng)的那根(也就是 10的倍數(shù)時(shí)的高度)
  private float mLineMidHeight = 30;  // mLineMidHeight 表示中間的高度(也就是 5 15 25 等時(shí)的高度)
  private float mLineMinHeight = 17;  // mLineMinHeight 表示最短的那個(gè)高度(也就是 1 2 3 4 等時(shí)的高度)

  private float mTextMarginTop = 10;  //o
  private float mTextSize = 30;     //尺子刻度下方數(shù)字 textsize

  private boolean mAlphaEnable = false; // 尺子 最左邊 最后邊是否需要透明 (透明效果更好點(diǎn))

  private float mTextHeight;      //尺子刻度下方數(shù)字 的高度

  private Paint mTextPaint;       // 尺子刻度下方數(shù)字( 也就是每隔10個(gè)出現(xiàn)的數(shù)值) paint
  private Paint mLinePaint;       // 尺子刻度 paint

  private int mTotalLine;        //共有多少條 刻度
  private int mMaxOffset;        //所有刻度 共有多長(zhǎng)
  private float mOffset;        // 默認(rèn)狀態(tài)下,mSelectorValue所在的位置 位于尺子總刻度的位置
  private int mLastX, mMove;
  private OnValueChangeListener mListener; // 滑動(dòng)后數(shù)值回調(diào)

  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 未選擇時(shí) 默認(rèn)的值 滑動(dòng)后表示當(dāng)前中間指針正在指著的值
   * @param minValue   最大數(shù)值
   * @param maxValue   最小的數(shù)值
   * @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; // 先畫(huà)默認(rèn)值在正中間,左右各一半的view。 多余部分暫時(shí)不畫(huà)(也就是從默認(rèn)值在中間,畫(huà)旁邊左右的刻度線(xiàn))
      }

      /*文字*/
      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);  // 在為整數(shù)時(shí),畫(huà) 數(shù)值
      }

      /*線(xiàn)條*/
      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(); //當(dāng)前的速度
    if (Math.abs(xVelocity) > mMinVelocity) {
      mScroller.fling(0, 0, (int) xVelocity, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
    }
  }


  /**
   * 滑動(dòng)結(jié)束后,若是指針在2條刻度之間時(shí),改變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();
  }


  /**
   * 滑動(dòng)后的操作
   */
  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);
    }
  }


  /**
   * 滑動(dòng)后的回調(diào)
   */
  public interface OnValueChangeListener {
    void onValueChange(float value);
  }

  @Override
  public void computeScroll() {
    super.computeScroll();
    if (mScroller.computeScrollOffset()) {   //mScroller.computeScrollOffset()返回 true表示滑動(dòng)還沒(méi)有結(jié)束
      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="點(diǎn)擊改變" />

  </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:可自行根據(jù)需要繪制線(xiàn)條和文字,上下選擇文字位置。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI