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

作者:676598624 时间:2022-06-30 20:09:27 

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

来源:https://blog.csdn.net/qq_26761229/article/details/80815138

标签:Android,标尺,滑动
0
投稿

猜你喜欢

  • javascript开发随笔3 开发iframe富文本编辑器的一点体会

    2021-09-25 09:41:28
  • java简单实现数组中的逆序对

    2022-06-26 02:23:17
  • Android多国语言转换Excel及Excel转换为string详解

    2022-10-30 08:07:02
  • java开发ShardingSphere的路由引擎类型示例详解

    2023-11-29 01:18:56
  • C#生成word记录实例解析

    2023-09-10 00:17:33
  • Android 在 res/layout 文件夹 下创建一个 子文件夹实例

    2021-07-31 22:50:21
  • Android利用Badge组件实现未读消息小红点

    2021-11-09 10:30:33
  • 详解用RxJava实现事件总线(Event Bus)

    2022-02-13 16:43:18
  • C#二进制序列化实例分析

    2022-09-21 01:43:38
  • java与js代码互调示例代码

    2022-11-09 20:19:05
  • 详解Spring循环依赖的解决方案

    2022-05-29 13:14:57
  • 基于MapReduce实现决策树算法

    2023-10-20 16:05:40
  • Hibernate5新特性介绍

    2023-01-02 16:28:09
  • Java实现的断点续传功能的示例代码

    2023-05-25 12:17:22
  • 浅析Spring Boot中的spring-boot-load模块

    2023-11-23 02:39:31
  • Javaweb mybatis接口开发实现过程详解

    2022-03-11 22:02:21
  • c语言实现的几种常用排序算法

    2022-02-23 04:04:11
  • 客户端实现蓝牙接收(C#)知识总结

    2021-11-21 22:17:11
  • 通过实例解析JMM和Volatile底层原理

    2023-05-20 19:10:48
  • hibernate-validator改进校验框架validator v0.4使用

    2023-01-22 21:08:07
  • asp之家 软件编程 m.aspxhome.com