Android自定義標尺滑動選擇值效果
本文實例為大家分享了Android實現(xiàn)滑動標尺選擇值,效果圖

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; // 最大數(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條線之間的距離
private float mLineWidth = 4; // 尺子刻度的寬度
private float mLineMaxHeight = 420; // 尺子刻度分為3中不同的高度。 mLineMaxHeight表示最長的那根(也就是 10的倍數(shù)時的高度)
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; //尺子刻度下方數(shù)字 textsize
private boolean mAlphaEnable = false; // 尺子 最左邊 最后邊是否需要透明 (透明效果更好點)
private float mTextHeight; //尺子刻度下方數(shù)字 的高度
private Paint mTextPaint; // 尺子刻度下方數(shù)字( 也就是每隔10個出現(xiàn)的數(shù)值) paint
private Paint mLinePaint; // 尺子刻度 paint
private int mTotalLine; //共有多少條 刻度
private int mMaxOffset; //所有刻度 共有多長
private float mOffset; // 默認狀態(tài)下,mSelectorValue所在的位置 位于尺子總刻度的位置
private int mLastX, mMove;
private OnValueChangeListener mListener; // 滑動后數(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 未選擇時 默認的值 滑動后表示當前中間指針正在指著的值
* @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; // 先畫默認值在正中間,左右各一半的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); // 在為整數(shù)時,畫 數(shù)值
}
/*線條*/
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);
}
}
/**
* 滑動后的回調(diào)
*/
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:可自行根據(jù)需要繪制線條和文字,上下選擇文字位置。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android Studio將AAR包發(fā)布到Maven本地倉庫的流程步驟
Android AAR文件是Android Archive文件的縮寫,是一種Android應用程序存檔文件格式,類似于JAR文件格式,它在Android Studio中被廣泛使用,本文給大家介紹了Android Studio將AAR包發(fā)布到Maven本地倉庫的流程步驟,需要的朋友可以參考下2025-03-03
Android API開發(fā)之SMS短信服務處理和獲取聯(lián)系人的方法
這篇文章主要介紹了Android API開發(fā)之SMS短信服務處理和獲取聯(lián)系人的方法,結合實例形式分析了Android API實現(xiàn)SMS短信發(fā)送及獲取聯(lián)系人的相關操作步驟與實現(xiàn)技巧,需要的朋友可以參考下2016-08-08
Android開發(fā)教程之獲取系統(tǒng)輸入法高度的正確姿勢
這篇文章主要給大家介紹了關于Android開發(fā)教程之獲取系統(tǒng)輸入法高度的正確姿勢,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Android具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-10-10
AccessibilityService實現(xiàn)微信發(fā)紅包功能
這篇文章主要為大家詳細介紹了AccessibilityService實現(xiàn)微信發(fā)紅包功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12
360瀏覽器文本框獲得焦點后被android軟鍵盤遮罩該怎么辦
最近接了個項目,項目需求是這樣的,站點上篩選按鈕點擊后彈出層(fixed),當輸入框獲取焦點以后彈出系統(tǒng)自帶的軟鍵盤,在android上十款瀏覽器挨個測試比對,發(fā)現(xiàn)在360瀏覽器彈出鍵盤以后獲取焦點的文本框被軟鍵盤覆蓋了,下面分享我的解決辦法2015-12-12
Flutter?阻止系統(tǒng)鍵盤彈出的優(yōu)雅方式
這篇文章主要為大家介紹了Flutter?阻止系統(tǒng)鍵盤彈出的優(yōu)雅方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11

