package com.kuanzhai.driver.utils.citypickerview.picker;
|
|
import android.animation.Animator;
|
import android.animation.AnimatorListenerAdapter;
|
import android.animation.ValueAnimator;
|
import android.content.Context;
|
import android.content.res.TypedArray;
|
import android.graphics.Canvas;
|
import android.graphics.Paint;
|
import android.graphics.Rect;
|
import android.graphics.RectF;
|
import android.graphics.Typeface;
|
import android.text.TextPaint;
|
import android.text.TextUtils;
|
import android.util.AttributeSet;
|
import android.util.TypedValue;
|
import android.view.MotionEvent;
|
import android.view.VelocityTracker;
|
import android.view.View;
|
import android.view.animation.DecelerateInterpolator;
|
|
import androidx.annotation.Nullable;
|
|
import com.xuexiang.xui.utils.ResUtils;
|
|
import java.lang.ref.WeakReference;
|
import java.math.BigDecimal;
|
|
import uk.co.chrisjenx.calligraphy.HasTypeface;
|
|
/**
|
* 刻度尺控件
|
*
|
* @author XUE
|
* @since 2019/4/2 16:33
|
*/
|
public class RulerView extends View implements HasTypeface {
|
/**
|
* 2个大刻度之间间距,默认为1
|
*/
|
private int mScaleLimit = 1;
|
/**
|
* 尺子高度
|
*/
|
private int mRulerHeight = 50;
|
/**
|
* 尺子和屏幕顶部以及结果之间的高度
|
*/
|
private int mRulerToResultGap = mRulerHeight / 4;
|
/**
|
* 刻度平分多少份
|
*/
|
private int mScaleCount = 10;
|
/**
|
* 刻度间距
|
*/
|
private int mScaleGap = 10;
|
/**
|
* 刻度最小值
|
*/
|
private int mMinScale = 0;
|
/**
|
* 第一次显示的刻度
|
*/
|
private float mFirstScale = 50f;
|
/**
|
* 刻度最大值
|
*/
|
private int mMaxScale = 100;
|
|
/**
|
* 背景颜色
|
*/
|
private int mBgColor;
|
/**
|
* 小刻度的颜色
|
*/
|
private int mSmallScaleColor;
|
/**
|
* 中刻度的颜色
|
*/
|
private int mMidScaleColor;
|
/**
|
* 大刻度的颜色
|
*/
|
private int mLargeScaleColor;
|
/**
|
* 刻度颜色
|
*/
|
private int mScaleNumColor;
|
/**
|
* 结果值颜色
|
*/
|
private int mResultNumColor;
|
/**
|
* kg颜色
|
*/
|
private String mUnit = "kg";
|
/**
|
* kg颜色
|
*/
|
private int mUnitColor;
|
/**
|
* 小刻度粗细大小
|
*/
|
private int mSmallScaleStroke = 2;
|
/**
|
* 中刻度粗细大小
|
*/
|
private int mMidScaleStroke = 3;
|
/**
|
* 大刻度粗细大小
|
*/
|
private int mLargeScaleStroke = 5;
|
/**
|
* 结果字体大小
|
*/
|
private int mResultNumTextSize = 20;
|
/**
|
* 刻度字体大小
|
*/
|
private int mScaleNumTextSize = 16;
|
/**
|
* 单位字体大小
|
*/
|
private int mUnitTextSize = 13;
|
/**
|
* 是否显示刻度结果
|
*/
|
private boolean mShowScaleResult = true;
|
/**
|
* 是否背景显示圆角
|
*/
|
private boolean mIsBgRoundRect = true;
|
/**
|
* 圆角大小
|
*/
|
private int mRoundRadius = 10;
|
/**
|
* 结果回调
|
*/
|
private OnChooseResultListener mOnChooseResultListener;
|
/**
|
* 滑动选择刻度
|
*/
|
private float mComputeScale = -1;
|
/**
|
* 当前刻度
|
*/
|
public float mCurrentScale = mFirstScale;
|
|
private ValueAnimator mValueAnimator;
|
private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
|
private String mResultText = String.valueOf(mFirstScale);
|
private Paint mBgPaint;
|
private Paint mSmallScalePaint;
|
private Paint mMidScalePaint;
|
private Paint mLagScalePaint;
|
private TextPaint mScaleNumPaint;
|
private TextPaint mResultNumPaint;
|
private TextPaint mUnitPaint;
|
private Rect mScaleNumRect;
|
private Rect mResultNumRect;
|
private Rect mKgRect;
|
private RectF mBgRect;
|
private int mHeight, mWidth;
|
private int mSmallScaleHeight;
|
private int mMidScaleHeight;
|
private int mLagScaleHeight;
|
private float mDownX;
|
private float mMoveX = 0;
|
private float mLastMoveX = 0;
|
private boolean mIsUp = false;
|
|
public RulerView(Context context) {
|
this(context, null);
|
}
|
|
public RulerView(Context context, @Nullable AttributeSet attrs) {
|
this(context, attrs, com.xuexiang.xui.R.attr.RulerViewStyle);
|
}
|
|
public RulerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
super(context, attrs, defStyleAttr);
|
initAttrs(context, attrs, defStyleAttr);
|
init();
|
}
|
|
/**
|
* 初始化属性
|
*
|
* @param attrs
|
* @param defStyleAttr
|
*/
|
private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
|
TypedArray a = context.obtainStyledAttributes(attrs, com.xuexiang.xui.R.styleable.RulerView, defStyleAttr, 0);
|
mScaleLimit = a.getInt(com.xuexiang.xui.R.styleable.RulerView_rv_scaleLimit, mScaleLimit);
|
mRulerHeight = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_rulerHeight, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mRulerHeight, getResources().getDisplayMetrics()));
|
mRulerToResultGap = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_rulerToResultGap, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mRulerToResultGap, getResources().getDisplayMetrics()));
|
mScaleCount = a.getInt(com.xuexiang.xui.R.styleable.RulerView_rv_scaleCount, mScaleCount);
|
mScaleGap = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_scaleGap, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mScaleGap, getResources().getDisplayMetrics()));
|
mMinScale = a.getInt(com.xuexiang.xui.R.styleable.RulerView_rv_minScale, mMinScale) / mScaleLimit;
|
mFirstScale = a.getFloat(com.xuexiang.xui.R.styleable.RulerView_rv_firstScale, mFirstScale) / mScaleLimit;
|
mMaxScale = a.getInt(com.xuexiang.xui.R.styleable.RulerView_rv_maxScale, mMaxScale) / mScaleLimit;
|
mBgColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_bgColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_bg_color));
|
mSmallScaleColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_smallScaleColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_small_scale_color));
|
mMidScaleColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_midScaleColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_mid_scale_color));
|
mLargeScaleColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_largeScaleColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_large_scale_color));
|
mScaleNumColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_scaleNumColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_scale_num_color));
|
mResultNumColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_resultNumColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_result_num_color));
|
mUnitColor = a.getColor(com.xuexiang.xui.R.styleable.RulerView_rv_unitColor, ResUtils.getColor(com.xuexiang.xui.R.color.default_ruler_view_unit_color));
|
String tempUnit = mUnit;
|
mUnit = a.getString(com.xuexiang.xui.R.styleable.RulerView_rv_unit);
|
if (TextUtils.isEmpty(mUnit)) {
|
mUnit = tempUnit;
|
}
|
mSmallScaleStroke = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_smallScaleStroke, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mSmallScaleStroke, getResources().getDisplayMetrics()));
|
mMidScaleStroke = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_midScaleStroke, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mMidScaleStroke, getResources().getDisplayMetrics()));
|
mLargeScaleStroke = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_largeScaleStroke, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mLargeScaleStroke, getResources().getDisplayMetrics()));
|
mResultNumTextSize = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_resultNumTextSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mResultNumTextSize, getResources().getDisplayMetrics()));
|
mScaleNumTextSize = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_scaleNumTextSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mScaleNumTextSize, getResources().getDisplayMetrics()));
|
mUnitTextSize = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_unitTextSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mUnitTextSize, getResources().getDisplayMetrics()));
|
mShowScaleResult = a.getBoolean(com.xuexiang.xui.R.styleable.RulerView_rv_showScaleResult, mShowScaleResult);
|
mIsBgRoundRect = a.getBoolean(com.xuexiang.xui.R.styleable.RulerView_rv_isBgRoundRect, mIsBgRoundRect);
|
mRoundRadius = a.getDimensionPixelSize(com.xuexiang.xui.R.styleable.RulerView_rv_roundRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mRoundRadius, getResources().getDisplayMetrics()));
|
a.recycle();
|
}
|
|
|
private void init() {
|
mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
mSmallScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
mMidScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
mLagScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
mScaleNumPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
mResultNumPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
mUnitPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
|
|
mBgPaint.setColor(mBgColor);
|
mSmallScalePaint.setColor(mSmallScaleColor);
|
mMidScalePaint.setColor(mMidScaleColor);
|
mLagScalePaint.setColor(mLargeScaleColor);
|
mScaleNumPaint.setColor(mScaleNumColor);
|
mResultNumPaint.setColor(mResultNumColor);
|
mUnitPaint.setColor(mUnitColor);
|
|
mResultNumPaint.setStyle(Paint.Style.FILL);
|
mUnitPaint.setStyle(Paint.Style.FILL);
|
mBgPaint.setStyle(Paint.Style.FILL);
|
mSmallScalePaint.setStyle(Paint.Style.FILL);
|
mMidScalePaint.setStyle(Paint.Style.FILL);
|
mLagScalePaint.setStyle(Paint.Style.FILL);
|
|
mLagScalePaint.setStrokeCap(Paint.Cap.ROUND);
|
mMidScalePaint.setStrokeCap(Paint.Cap.ROUND);
|
mSmallScalePaint.setStrokeCap(Paint.Cap.ROUND);
|
|
mSmallScalePaint.setStrokeWidth(mSmallScaleStroke);
|
mMidScalePaint.setStrokeWidth(mMidScaleStroke);
|
mLagScalePaint.setStrokeWidth(mLargeScaleStroke);
|
|
mResultNumPaint.setTextSize(mResultNumTextSize);
|
mUnitPaint.setTextSize(mUnitTextSize);
|
mScaleNumPaint.setTextSize(mScaleNumTextSize);
|
|
mBgRect = new RectF();
|
mResultNumRect = new Rect();
|
mScaleNumRect = new Rect();
|
mKgRect = new Rect();
|
|
mResultNumPaint.getTextBounds(mResultText, 0, mResultText.length(), mResultNumRect);
|
mUnitPaint.getTextBounds(mResultText, 0, 1, mKgRect);
|
|
mSmallScaleHeight = mRulerHeight / 4;
|
mMidScaleHeight = mRulerHeight / 2;
|
mLagScaleHeight = mRulerHeight / 2 + 5;
|
mValueAnimator = new ValueAnimator();
|
|
}
|
|
@Override
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
int heightModule = MeasureSpec.getMode(heightMeasureSpec);
|
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
|
switch (heightModule) {
|
case MeasureSpec.AT_MOST:
|
mHeight = mRulerHeight + (mShowScaleResult ? mResultNumRect.height() : 0) + mRulerToResultGap * 2 + getPaddingTop() + getPaddingBottom();
|
break;
|
case MeasureSpec.UNSPECIFIED:
|
case MeasureSpec.EXACTLY:
|
mHeight = heightSize + getPaddingTop() + getPaddingBottom();
|
break;
|
default:
|
break;
|
}
|
|
mWidth = widthSize + getPaddingLeft() + getPaddingRight();
|
|
setMeasuredDimension(mWidth, mHeight);
|
|
}
|
|
@Override
|
protected void onDraw(Canvas canvas) {
|
drawBg(canvas);
|
drawScaleAndNum(canvas);
|
drawResultText(canvas, mResultText);
|
}
|
|
@Override
|
public boolean onTouchEvent(MotionEvent event) {
|
if (getParent() != null) {
|
//拦截事件,不让父布局获取
|
getParent().requestDisallowInterceptTouchEvent(true);
|
}
|
|
float currentX = event.getX();
|
mIsUp = false;
|
mVelocityTracker.computeCurrentVelocity(500);
|
mVelocityTracker.addMovement(event);
|
switch (event.getAction()) {
|
case MotionEvent.ACTION_DOWN:
|
//按下时如果属性动画还没执行完,就终止,记录下当前按下点的位置
|
if (mValueAnimator != null && mValueAnimator.isRunning()) {
|
mValueAnimator.end();
|
mValueAnimator.cancel();
|
}
|
mDownX = event.getX();
|
break;
|
case MotionEvent.ACTION_MOVE:
|
//滑动时候,通过假设的滑动距离,做超出左边界以及右边界的限制。
|
mMoveX = currentX - mDownX + mLastMoveX;
|
if (mMoveX >= mWidth / 2) {
|
mMoveX = mWidth / 2;
|
} else if (mMoveX <= getWhichScaleMoveX(mMaxScale)) {
|
mMoveX = getWhichScaleMoveX(mMaxScale);
|
}
|
break;
|
case MotionEvent.ACTION_UP:
|
//手指抬起时候制造惯性滑动
|
mLastMoveX = mMoveX;
|
int xVelocity = (int) mVelocityTracker.getXVelocity();
|
autoVelocityScroll(xVelocity);
|
mVelocityTracker.clear();
|
break;
|
default:
|
break;
|
}
|
invalidate();
|
return true;
|
}
|
|
private void autoVelocityScroll(int xVelocity) {
|
//惯性滑动的代码,速率和滑动距离,以及滑动时间需要控制的很好,应该网上已经有关于这方面的算法了吧。。这里是经过N次测试调节出来的惯性滑动
|
if (Math.abs(xVelocity) < 50) {
|
mIsUp = true;
|
return;
|
}
|
if (mValueAnimator.isRunning()) {
|
return;
|
}
|
mValueAnimator = ValueAnimator.ofInt(0, xVelocity / 20).setDuration(Math.abs(xVelocity / 10));
|
mValueAnimator.setInterpolator(new DecelerateInterpolator());
|
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
@Override
|
public void onAnimationUpdate(ValueAnimator animation) {
|
mMoveX += (int) animation.getAnimatedValue();
|
if (mMoveX >= mWidth / 2) {
|
mMoveX = mWidth / 2;
|
} else if (mMoveX <= getWhichScaleMoveX(mMaxScale)) {
|
mMoveX = getWhichScaleMoveX(mMaxScale);
|
}
|
mLastMoveX = mMoveX;
|
invalidate();
|
}
|
|
});
|
mValueAnimator.addListener(new AnimatorListenerAdapter() {
|
@Override
|
public void onAnimationEnd(Animator animation) {
|
mIsUp = true;
|
invalidate();
|
}
|
});
|
|
mValueAnimator.start();
|
}
|
|
private float getWhichScaleMoveX(float scale) {
|
return mWidth / 2 - mScaleGap * mScaleCount * (scale - mMinScale);
|
}
|
|
private void drawScaleAndNum(Canvas canvas) {
|
canvas.translate(0, (mShowScaleResult ? mResultNumRect.height() : 0) + mRulerToResultGap);//移动画布到结果值的下面
|
|
int num1;//确定刻度位置
|
float num2;
|
|
if (mFirstScale != -1) { //第一次进来的时候计算出默认刻度对应的假设滑动的距离moveX
|
mMoveX = getWhichScaleMoveX(mFirstScale); //如果设置了默认滑动位置,计算出需要滑动的距离
|
mLastMoveX = mMoveX;
|
mFirstScale = -1; //将结果置为-1,下次不再计算初始位置
|
}
|
|
if (mComputeScale != -1) {//弹性滑动到目标刻度
|
mLastMoveX = mMoveX;
|
if (mValueAnimator != null && !mValueAnimator.isRunning()) {
|
mValueAnimator = ValueAnimator.ofFloat(getWhichScaleMoveX(mCurrentScale), getWhichScaleMoveX(mComputeScale));
|
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
@Override
|
public void onAnimationUpdate(ValueAnimator animation) {
|
mMoveX = (float) animation.getAnimatedValue();
|
mLastMoveX = mMoveX;
|
invalidate();
|
}
|
});
|
mValueAnimator.addListener(new AnimatorListenerAdapter() {
|
@Override
|
public void onAnimationEnd(Animator animation) {
|
super.onAnimationEnd(animation);
|
//这里是滑动结束时候回调给使用者的结果值
|
mComputeScale = -1;
|
}
|
});
|
mValueAnimator.setDuration(Math.abs((long) ((getWhichScaleMoveX(mComputeScale) - getWhichScaleMoveX(mCurrentScale)) / 100)));
|
mValueAnimator.start();
|
}
|
}
|
|
num1 = -(int) (mMoveX / mScaleGap); //滑动刻度的整数部分
|
num2 = (mMoveX % mScaleGap); //滑动刻度的小数部分
|
|
canvas.save(); //保存当前画布
|
|
int rulerRight = 0; //准备开始绘制当前屏幕,从最左面开始
|
|
if (mIsUp) { //这部分代码主要是计算手指抬起时,惯性滑动结束时,刻度需要停留的位置
|
num2 = ((mMoveX - mWidth / 2 % mScaleGap) % mScaleGap); //计算滑动位置距离整点刻度的小数部分距离
|
if (num2 <= 0) {
|
num2 = mScaleGap - Math.abs(num2);
|
}
|
int leftScroll = (int) Math.abs(num2); //当前滑动位置距离左边整点刻度的距离
|
int rightScroll = (int) (mScaleGap - Math.abs(num2)); //当前滑动位置距离右边整点刻度的距离
|
|
float moveX2 = num2 <= mScaleGap / 2 ? mMoveX - leftScroll : mMoveX + rightScroll; //最终计算出当前位置到整点刻度位置需要滑动的距离
|
|
if (mValueAnimator != null && !mValueAnimator.isRunning()) { //手指抬起,并且当前没有惯性滑动在进行,创建一个惯性滑动
|
mValueAnimator = ValueAnimator.ofFloat(mMoveX, moveX2);
|
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
@Override
|
public void onAnimationUpdate(ValueAnimator animation) {
|
mMoveX = (float) animation.getAnimatedValue(); //不断滑动去更新新的位置
|
mLastMoveX = mMoveX;
|
invalidate();
|
}
|
});
|
mValueAnimator.addListener(new AnimatorListenerAdapter() { //增加一个监听,用来返回给使用者滑动结束后的最终结果刻度值
|
@Override
|
public void onAnimationEnd(Animator animation) {
|
super.onAnimationEnd(animation);
|
//这里是滑动结束时候回调给使用者的结果值
|
if (mOnChooseResultListener != null) {
|
mOnChooseResultListener.onEndResult(mResultText);
|
}
|
}
|
});
|
mValueAnimator.setDuration(300);
|
mValueAnimator.start();
|
mIsUp = false;
|
}
|
//重新计算当前滑动位置的整数以及小数位置
|
num1 = (int) -(mMoveX / mScaleGap);
|
num2 = (mMoveX % mScaleGap);
|
}
|
|
//不加该偏移的话,滑动时刻度不会落在0~1之间只会落在整数上面,其实这个都能设置一种模式了,毕竟初衷就是指针不会落在小数上面
|
canvas.translate(num2, 0);
|
|
//这里是滑动时候不断回调给使用者的结果值
|
mCurrentScale = new WeakReference<>(new BigDecimal(((mWidth / 2 - mMoveX) / (mScaleGap * mScaleCount) + mMinScale) * mScaleLimit)).get().setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();
|
|
mResultText = String.valueOf(mCurrentScale);
|
|
|
if (mOnChooseResultListener != null) {
|
mOnChooseResultListener.onScrollResult(mResultText); //接口不断回调给使用者结果值
|
}
|
//绘制当前屏幕可见刻度,不需要裁剪屏幕,while循环只会执行·屏幕宽度/刻度宽度·次,大部分的绘制都是if(curDis<mWidth)这样子内存暂用相对来说会比较高。。
|
while (rulerRight < mWidth) {
|
if (num1 % mScaleCount == 0) { //绘制整点刻度以及文字
|
if ((mMoveX >= 0 && rulerRight < mMoveX - mScaleGap) || mWidth / 2 - rulerRight <= getWhichScaleMoveX(mMaxScale + 1) - mMoveX) {
|
//当滑动出范围的话,不绘制,去除左右边界
|
} else {
|
//绘制刻度,绘制刻度数字
|
canvas.drawLine(0, 0, 0, mMidScaleHeight, mMidScalePaint);
|
mScaleNumPaint.getTextBounds(num1 / mScaleGap + mMinScale + "", 0, (num1 / mScaleGap + mMinScale + "").length(), mScaleNumRect);
|
canvas.drawText((num1 / mScaleCount + mMinScale) * mScaleLimit + "", -mScaleNumRect.width() / 2, mLagScaleHeight +
|
(mRulerHeight - mLagScaleHeight) / 2 + mScaleNumRect.height(), mScaleNumPaint);
|
|
}
|
|
} else { //绘制小数刻度
|
if ((mMoveX >= 0 && rulerRight < mMoveX) || mWidth / 2 - rulerRight < getWhichScaleMoveX(mMaxScale) - mMoveX) {
|
//当滑动出范围的话,不绘制,去除左右边界
|
} else {
|
//绘制小数刻度
|
canvas.drawLine(0, 0, 0, mSmallScaleHeight, mSmallScalePaint);
|
}
|
}
|
++num1; //刻度加1
|
rulerRight += mScaleGap; //绘制屏幕的距离在原有基础上+1个刻度间距
|
canvas.translate(mScaleGap, 0); //移动画布到下一个刻度
|
}
|
|
canvas.restore();
|
//绘制屏幕中间用来选中刻度的最大刻度
|
canvas.drawLine(mWidth / 2, 0, mWidth / 2, mLagScaleHeight, mLagScalePaint);
|
|
}
|
|
//绘制上面的结果 结果值+单位
|
private void drawResultText(Canvas canvas, String resultText) {
|
if (!mShowScaleResult) { //判断用户是否设置需要显示当前刻度值,如果否则取消绘制
|
return;
|
}
|
canvas.translate(0, -mResultNumRect.height() - mRulerToResultGap / 2); //移动画布到正确的位置来绘制结果值
|
mResultNumPaint.getTextBounds(resultText, 0, resultText.length(), mResultNumRect);
|
canvas.drawText(resultText, mWidth / 2 - mResultNumRect.width() / 2, mResultNumRect.height(), //绘制当前刻度结果值
|
mResultNumPaint);
|
int resultNumRight = mWidth / 2 + mResultNumRect.width() / 2 + 10;
|
canvas.drawText(mUnit, resultNumRight, mKgRect.height() + 2, mUnitPaint); //在当前刻度结果值的又面10px的位置绘制单位
|
}
|
|
private void drawBg(Canvas canvas) {
|
mBgRect.set(0, 0, mWidth, mHeight);
|
if (mIsBgRoundRect) {
|
//椭圆的用于圆形角x-radius
|
canvas.drawRoundRect(mBgRect, mRoundRadius, mRoundRadius, mBgPaint);
|
} else {
|
canvas.drawRect(mBgRect, mBgPaint);
|
}
|
}
|
|
private void computeScrollTo(float scale) {
|
scale = scale / mScaleLimit;
|
if (scale < mMinScale || scale > mMaxScale) {
|
return;
|
}
|
mComputeScale = scale;
|
invalidate();
|
}
|
|
@Override
|
public void setTypeface(Typeface typeface) {
|
if (mResultNumPaint != null) {
|
mResultNumPaint.setTypeface(typeface);
|
}
|
if (mUnitPaint != null) {
|
mUnitPaint.setTypeface(typeface);
|
}
|
if (mScaleNumPaint != null) {
|
mScaleNumPaint.setTypeface(typeface);
|
}
|
}
|
|
/**
|
* 选择结果监听
|
*/
|
public interface OnChooseResultListener {
|
/**
|
* 滑动选择结束
|
*
|
* @param result
|
*/
|
void onEndResult(String result);
|
|
/**
|
* 开始滑动选择
|
*
|
* @param result
|
*/
|
void onScrollResult(String result);
|
}
|
|
public void setRulerHeight(int rulerHeight) {
|
this.mRulerHeight = rulerHeight;
|
invalidate();
|
}
|
|
public void setRulerToResultGap(int rulerToResultGap) {
|
this.mRulerToResultGap = rulerToResultGap;
|
invalidate();
|
}
|
|
public void setScaleCount(int scaleCount) {
|
this.mScaleCount = scaleCount;
|
invalidate();
|
}
|
|
public void setScaleGap(int scaleGap) {
|
this.mScaleGap = scaleGap;
|
invalidate();
|
}
|
|
public void setMinScale(int minScale) {
|
this.mMinScale = minScale;
|
invalidate();
|
}
|
|
public void setFirstScale(float firstScale) {
|
this.mFirstScale = firstScale;
|
invalidate();
|
}
|
|
public void setMaxScale(int maxScale) {
|
this.mMaxScale = maxScale;
|
invalidate();
|
}
|
|
public void setBgColor(int bgColor) {
|
this.mBgColor = bgColor;
|
invalidate();
|
}
|
|
public void setSmallScaleColor(int smallScaleColor) {
|
this.mSmallScaleColor = smallScaleColor;
|
invalidate();
|
}
|
|
public void setMidScaleColor(int midScaleColor) {
|
this.mMidScaleColor = midScaleColor;
|
invalidate();
|
}
|
|
public void setLargeScaleColor(int largeScaleColor) {
|
this.mLargeScaleColor = largeScaleColor;
|
}
|
|
public void setScaleNumColor(int scaleNumColor) {
|
this.mScaleNumColor = scaleNumColor;
|
invalidate();
|
}
|
|
public void setResultNumColor(int resultNumColor) {
|
this.mResultNumColor = resultNumColor;
|
invalidate();
|
}
|
|
public void setUnit(String unit) {
|
this.mUnit = unit;
|
invalidate();
|
}
|
|
public void setUnitColor(int unitColor) {
|
this.mUnitColor = unitColor;
|
invalidate();
|
}
|
|
public void setSmallScaleStroke(int smallScaleStroke) {
|
this.mSmallScaleStroke = smallScaleStroke;
|
invalidate();
|
}
|
|
public void setMidScaleStroke(int midScaleStroke) {
|
this.mMidScaleStroke = midScaleStroke;
|
invalidate();
|
}
|
|
public void setLargeScaleStroke(int largeScaleStroke) {
|
this.mLargeScaleStroke = largeScaleStroke;
|
invalidate();
|
}
|
|
public void setResultNumTextSize(int resultNumTextSize) {
|
this.mResultNumTextSize = resultNumTextSize;
|
invalidate();
|
}
|
|
public void setScaleNumTextSize(int scaleNumTextSize) {
|
this.mScaleNumTextSize = scaleNumTextSize;
|
invalidate();
|
}
|
|
public void setUnitTextSize(int unitTextSize) {
|
this.mUnitTextSize = unitTextSize;
|
invalidate();
|
}
|
|
public void setShowScaleResult(boolean showScaleResult) {
|
this.mShowScaleResult = showScaleResult;
|
invalidate();
|
}
|
|
public void setIsBgRoundRect(boolean bgRoundRect) {
|
mIsBgRoundRect = bgRoundRect;
|
invalidate();
|
}
|
|
public void setScaleLimit(int scaleLimit) {
|
this.mScaleLimit = scaleLimit;
|
invalidate();
|
}
|
|
/**
|
* 设置刻度尺的值
|
*
|
* @param value
|
*/
|
public void setCurrentValue(float value) {
|
computeScrollTo(value);
|
}
|
|
/**
|
* 获取当前刻度尺的刻度
|
*
|
* @return
|
*/
|
public float getCurrentValue() {
|
return mCurrentScale;
|
}
|
|
/**
|
* 获取选择值
|
*
|
* @return
|
*/
|
public String getSelectValue() {
|
return mResultText;
|
}
|
|
/**
|
* 设置选择监听
|
*
|
* @param onChooseResultListener
|
* @return
|
*/
|
public RulerView setOnChooseResultListener(OnChooseResultListener onChooseResultListener) {
|
this.mOnChooseResultListener = onChooseResultListener;
|
return this;
|
}
|
}
|