安卓自定义尺子控件RulerView

这篇具有很好参考价值的文章主要介绍了安卓自定义尺子控件RulerView。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

安卓自定义尺子控件RulerView,Android开发,练习代码,android,kotlin
MyRulerView.java

package com.example.myapplication;


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.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 java.lang.ref.WeakReference;
import java.math.BigDecimal;

public class MyRulerView extends View {
    private static final String TAG = "MyRulerView";
    /**
     * 2个大刻度之间间距,默认为1
     */
    private int scaleLimit = 1;
    /**
     * 尺子高度
     */
    private int rulerHeight = 50;

    /**
     * 尺子和屏幕顶部以及结果之间的高度
     */
    private int rulerToResultgap = rulerHeight / 4;
    /**
     * 刻度平分多少份
     */
    private int scaleCount = 10;  //刻度评分多少份
    /**
     * 刻度间距
     */
    private int scaleGap = 20;
    /**
     * 刻度最小值
     */
    private int minScale = 0;
    /**
     * 第一次显示的刻度
     */
    private float firstScale = 50f;
    /**
     * 刻度最大值
     */
    private int maxScale = 100;

    /**
     * 背景颜色
     */
    private int bgColor = 0xfffcfffc;
    /**
     * 小刻度的颜色
     */
    private int smallScaleColor = 0xff999999;
    /**
     * 中刻度的颜色
     */
    private int midScaleColor = 0xff666666;
    /**
     * 大刻度的颜色
     */
    private int largeScaleColor = 0xff50b586;
    /**
     * 刻度颜色
     */
    private int scaleNumColor = 0xff333333;
    /**
     * 结果值颜色
     */
    private int resultNumColor = 0xff50b586;
    /**
     * 单位kg
     */
    private String unit = "kg";
    /**
     * kg颜色
     */
    private int unitColor = 0xff50b586;
    /**
     * 小刻度粗细大小
     */
    private int smallScaleStroke = 1;
    /**
     * 中刻度粗细大小
     */
    private int midScaleStroke = 2;
    /**
     * 大刻度粗细大小
     */
    private int largeScaleStroke = 3;
    /**
     * 结果字体大小
     */
    private int resultNumTextSize = 20;
    /**
     * 刻度字体大小
     */
    private int scaleNumTextSize = 16;
    /**
     * 单位字体大小
     */
    private int unitTextSize = 13;
    /**
     * 是否显示刻度结果
     */
    private boolean showScaleResult = true;
    /**
     * 是否显示刻度结果为整数
     */
    private boolean showScaleResultInteger = false;
    /**
     * 是否背景显示圆角
     */
    private boolean isBgRoundRect = true;

    /**
     * 结果回调
     */
    private MyRulerView.OnChooseResulterListener onChooseResulterListener;
    /**
     * 滑动选择刻度
     */
    private float computeScale = -1;
    /**
     * 当前刻度
     */
    public float currentScale = firstScale;

    private ValueAnimator valueAnimator;
    private VelocityTracker velocityTracker = VelocityTracker.obtain();
    private String resultText = String.valueOf(firstScale);
    private Paint bgPaint;
    private Paint smallScalePaint;
    private Paint midScalePaint;
    private Paint lagScalePaint;
    private Paint scaleNumPaint;
    private Paint resultNumPaint;
    private Paint kgPaint;
    private Rect scaleNumRect;
    private Rect resultNumRect;
    private Rect kgRect;
    private RectF bgRect;
    private int height, width;
    private int smallScaleHeight;
    private int midScaleHeight;
    private int lagScaleHeight;
    private int rulerRight = 0;
    private int resultNumRight;
    private float downX;
    private float moveX = 0;
    private float currentX;
    private float lastMoveX = 0;
    private boolean isUp = false;
    private int leftScroll;
    private int rightScroll;
    private int xVelocity;

    public MyRulerView(Context context) {
        this(context, null);
    }

    public MyRulerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRulerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setAttr(attrs, defStyleAttr);
        init();
    }

    public void setOnChooseResulterListener(MyRulerView.OnChooseResulterListener onChooseResulterListener) {
        this.onChooseResulterListener = onChooseResulterListener;
    }

    private void setAttr(AttributeSet attrs, int defStyleAttr) {

        TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MyRulerView, defStyleAttr, 0);

        scaleLimit = a.getInt(R.styleable.MyRulerView_scaleLimit, scaleLimit);

        rulerHeight = a.getDimensionPixelSize(R.styleable.MyRulerView_rulerHeight, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, rulerHeight, getResources().getDisplayMetrics()));

        rulerToResultgap = a.getDimensionPixelSize(R.styleable.MyRulerView_rulerToResultgap, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, rulerToResultgap, getResources().getDisplayMetrics()));

        scaleCount = a.getInt(R.styleable.MyRulerView_scaleCount, scaleCount);

        scaleGap = a.getDimensionPixelSize(R.styleable.MyRulerView_scaleGap, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, scaleGap, getResources().getDisplayMetrics()));

        minScale = a.getInt(R.styleable.MyRulerView_minScale, minScale) / scaleLimit;

        firstScale = a.getFloat(R.styleable.MyRulerView_firstScale, firstScale) / scaleLimit;

        maxScale = a.getInt(R.styleable.MyRulerView_maxScale, maxScale) / scaleLimit;

        bgColor = a.getColor(R.styleable.MyRulerView_bgColor, bgColor);

        smallScaleColor = a.getColor(R.styleable.MyRulerView_smallScaleColor, smallScaleColor);

        midScaleColor = a.getColor(R.styleable.MyRulerView_midScaleColor, midScaleColor);

        largeScaleColor = a.getColor(R.styleable.MyRulerView_largeScaleColor, largeScaleColor);

        scaleNumColor = a.getColor(R.styleable.MyRulerView_scaleNumColor, scaleNumColor);

        resultNumColor = a.getColor(R.styleable.MyRulerView_resultNumColor, resultNumColor);

        unitColor = a.getColor(R.styleable.MyRulerView_unitColor, unitColor);

        String tempUnit = unit;
        unit = a.getString(R.styleable.MyRulerView_unit);
        if (TextUtils.isEmpty(unit)) {
            unit = tempUnit;
        }

        smallScaleStroke = a.getDimensionPixelSize(R.styleable.MyRulerView_smallScaleStroke, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, smallScaleStroke, getResources().getDisplayMetrics()));

        midScaleStroke = a.getDimensionPixelSize(R.styleable.MyRulerView_midScaleStroke, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, midScaleStroke, getResources().getDisplayMetrics()));
        largeScaleStroke = a.getDimensionPixelSize(R.styleable.MyRulerView_largeScaleStroke, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, largeScaleStroke, getResources().getDisplayMetrics()));
        resultNumTextSize = a.getDimensionPixelSize(R.styleable.MyRulerView_resultNumTextSize, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, resultNumTextSize, getResources().getDisplayMetrics()));

        scaleNumTextSize = a.getDimensionPixelSize(R.styleable.MyRulerView_scaleNumTextSize, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, scaleNumTextSize, getResources().getDisplayMetrics()));

        unitTextSize = a.getDimensionPixelSize(R.styleable.MyRulerView_unitTextSize, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, unitTextSize, getResources().getDisplayMetrics()));

        showScaleResult = a.getBoolean(R.styleable.MyRulerView_showScaleResult, showScaleResult);
        showScaleResultInteger = a.getBoolean(R.styleable.MyRulerView_showScaleResultInteger, showScaleResultInteger);
        isBgRoundRect = a.getBoolean(R.styleable.MyRulerView_isBgRoundRect, isBgRoundRect);

        a.recycle();
    }


    private void init() {
        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        smallScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        midScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        lagScalePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        scaleNumPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        resultNumPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        kgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        bgPaint.setColor(bgColor);
        smallScalePaint.setColor(smallScaleColor);
        midScalePaint.setColor(midScaleColor);
        lagScalePaint.setColor(largeScaleColor);
        scaleNumPaint.setColor(scaleNumColor);
        resultNumPaint.setColor(resultNumColor);
        kgPaint.setColor(unitColor);

        resultNumPaint.setStyle(Paint.Style.FILL);
        kgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setStyle(Paint.Style.FILL);
        smallScalePaint.setStyle(Paint.Style.FILL);
        midScalePaint.setStyle(Paint.Style.FILL);
        lagScalePaint.setStyle(Paint.Style.FILL);

        lagScalePaint.setStrokeCap(Paint.Cap.ROUND);
        midScalePaint.setStrokeCap(Paint.Cap.ROUND);
        smallScalePaint.setStrokeCap(Paint.Cap.ROUND);

        smallScalePaint.setStrokeWidth(smallScaleStroke);
        midScalePaint.setStrokeWidth(midScaleStroke);
        lagScalePaint.setStrokeWidth(largeScaleStroke);

        resultNumPaint.setTextSize(resultNumTextSize);
        kgPaint.setTextSize(unitTextSize);
        scaleNumPaint.setTextSize(scaleNumTextSize);

        bgRect = new RectF();
        resultNumRect = new Rect();
        scaleNumRect = new Rect();
        kgRect = new Rect();

        resultNumPaint.getTextBounds(resultText, 0, resultText.length(), resultNumRect);
        kgPaint.getTextBounds(resultText, 0, 1, kgRect);

        smallScaleHeight = rulerHeight / 4;
        midScaleHeight = rulerHeight / 2;
        lagScaleHeight = rulerHeight / 2 + 5;
        valueAnimator = 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:
            case MeasureSpec.UNSPECIFIED:
                height = rulerHeight + (showScaleResult ? resultNumRect.height() : 0) + rulerToResultgap * 2 + getPaddingTop() + getPaddingBottom();
                break;
            case MeasureSpec.EXACTLY:
                height = heightSize + getPaddingTop() + getPaddingBottom();
                break;
        }

        width = widthSize + getPaddingLeft() + getPaddingRight();

        setMeasuredDimension(width, height);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawBg(canvas);
        drawScaleAndNum(canvas);
        drawResultText(canvas, resultText);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        currentX = event.getX();
        isUp = false;
        velocityTracker.computeCurrentVelocity(500);
        velocityTracker.addMovement(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //按下时如果属性动画还没执行完,就终止,记录下当前按下点的位置
                if (valueAnimator != null && valueAnimator.isRunning()) {
                    valueAnimator.end();
                    valueAnimator.cancel();
                }
                downX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                //滑动时候,通过假设的滑动距离,做超出左边界以及右边界的限制。
                moveX = currentX - downX + lastMoveX;
                if (moveX >= width / 2) {
                    moveX = width / 2;
                } else if (moveX <= getWhichScalMovex(maxScale)) {
                    moveX = getWhichScalMovex(maxScale);
                }
                break;
            case MotionEvent.ACTION_UP:
                //手指抬起时候制造惯性滑动
                lastMoveX = moveX;
                xVelocity = (int) velocityTracker.getXVelocity();
                autoVelocityScroll(xVelocity);
                velocityTracker.clear();
                break;
        }
        invalidate();
        return true;
    }

    private void autoVelocityScroll(int xVelocity) {
        //惯性滑动的代码,速率和滑动距离,以及滑动时间需要控制的很好,应该网上已经有关于这方面的算法了吧。。这里是经过N次测试调节出来的惯性滑动
        if (Math.abs(xVelocity) < 50) {
            isUp = true;
            return;
        }
        if (valueAnimator.isRunning()) {
            return;
        }
        valueAnimator = ValueAnimator.ofInt(0, xVelocity / 20).setDuration(Math.abs(xVelocity / 10));
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                moveX += (int) animation.getAnimatedValue();
                if (moveX >= width / 2) {
                    moveX = width / 2;
                } else if (moveX <= getWhichScalMovex(maxScale)) {
                    moveX = getWhichScalMovex(maxScale);
                }
                lastMoveX = moveX;
                invalidate();
            }

        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                isUp = true;
                invalidate();
            }
        });

        valueAnimator.start();
    }

    private float getWhichScalMovex(float scale) {
        return width / 2 - scaleGap * scaleCount * (scale - minScale);
    }

    private void drawScaleAndNum(Canvas canvas) {
        canvas.translate(0, (showScaleResult ? resultNumRect.height() : 0) + rulerToResultgap);//移动画布到结果值的下面

        int num1;//确定刻度位置
        float num2;

        if (firstScale != -1) {   //第一次进来的时候计算出默认刻度对应的假设滑动的距离moveX
            moveX = getWhichScalMovex(firstScale);          //如果设置了默认滑动位置,计算出需要滑动的距离
            lastMoveX = moveX;
            firstScale = -1;                                //将结果置为-1,下次不再计算初始位置
        }

        if (computeScale != -1) {//弹性滑动到目标刻度
            lastMoveX = moveX;
            if (valueAnimator != null && !valueAnimator.isRunning()) {
                valueAnimator = ValueAnimator.ofFloat(getWhichScalMovex(currentScale), getWhichScalMovex(computeScale));
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        moveX = (float) animation.getAnimatedValue();
                        lastMoveX = moveX;
                        invalidate();
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        //这里是滑动结束时候回调给使用者的结果值
                        computeScale = -1;
                    }
                });
                valueAnimator.setDuration(Math.abs((long) ((getWhichScalMovex(computeScale) - getWhichScalMovex(currentScale)) / 100)));
                valueAnimator.start();
            }
        }

        num1 = -(int) (moveX / scaleGap);                   //滑动刻度的整数部分
        num2 = (moveX % scaleGap);                         //滑动刻度的小数部分

        canvas.save();                                      //保存当前画布

        rulerRight = 0;                                    //准备开始绘制当前屏幕,从最左面开始

        if (isUp) {   //这部分代码主要是计算手指抬起时,惯性滑动结束时,刻度需要停留的位置
            num2 = ((moveX - width / 2 % scaleGap) % scaleGap);     //计算滑动位置距离整点刻度的小数部分距离
            if (num2 <= 0) {
                num2 = scaleGap - Math.abs(num2);
            }
            leftScroll = (int) Math.abs(num2);                        //当前滑动位置距离左边整点刻度的距离
            rightScroll = (int) (scaleGap - Math.abs(num2));         //当前滑动位置距离右边整点刻度的距离

            float moveX2 = num2 <= scaleGap / 2 ? moveX - leftScroll : moveX + rightScroll; //最终计算出当前位置到整点刻度位置需要滑动的距离

            if (valueAnimator != null && !valueAnimator.isRunning()) {      //手指抬起,并且当前没有惯性滑动在进行,创建一个惯性滑动
                valueAnimator = ValueAnimator.ofFloat(moveX, moveX2);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        moveX = (float) animation.getAnimatedValue();            //不断滑动去更新新的位置
                        lastMoveX = moveX;
                        invalidate();
                    }
                });
                valueAnimator.addListener(new AnimatorListenerAdapter() {       //增加一个监听,用来返回给使用者滑动结束后的最终结果刻度值
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        //这里是滑动结束时候回调给使用者的结果值
                        if (onChooseResulterListener != null) {
                            onChooseResulterListener.onEndResult(resultText, currentScale);
                        }
                    }
                });
                valueAnimator.setDuration(300);
                valueAnimator.start();
                isUp = false;
            }

            num1 = (int) -(moveX / scaleGap);                //重新计算当前滑动位置的整数以及小数位置
            num2 = (moveX % scaleGap);
        }


        canvas.translate(num2, 0);    //不加该偏移的话,滑动时刻度不会落在0~1之间只会落在整数上面,其实这个都能设置一种模式了,毕竟初衷就是指针不会落在小数上面

        //这里是滑动时候不断回调给使用者的结果值
        currentScale = new WeakReference<>(new BigDecimal(((width / 2 - moveX) / (scaleGap * scaleCount) + minScale) * scaleLimit)).get().setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();

        resultText = String.valueOf(currentScale);


        if (onChooseResulterListener != null) {
            onChooseResulterListener.onScrollResult(resultText); //接口不断回调给使用者结果值
        }
        //绘制当前屏幕可见刻度,不需要裁剪屏幕,while循环只会执行·屏幕宽度/刻度宽度·次,大部分的绘制都是if(curDis<width)这样子内存暂用相对来说会比较高。。
        while (rulerRight < width) {
            if (num1 % scaleCount == 0) {    //绘制整点刻度以及文字
                if ((moveX >= 0 && rulerRight < moveX - scaleGap) || width / 2 - rulerRight <= getWhichScalMovex(maxScale + 1) - moveX) {
                    //当滑动出范围的话,不绘制,去除左右边界
                } else {
                    //绘制刻度,绘制刻度数字
                    canvas.drawLine(0, 0, 0, midScaleHeight, midScalePaint);
                    String scaleS = (num1 / scaleCount + minScale) * scaleLimit + "";
                    scaleNumPaint.getTextBounds(scaleS, 0, scaleS.length(), scaleNumRect);

                    canvas.drawText(scaleS, -scaleNumRect.width() / 2, (float) (lagScaleHeight +
                            (rulerHeight - lagScaleHeight) / 2 + scaleNumRect.height()), scaleNumPaint);

                }

            } else {   //绘制小数刻度
                if ((moveX >= 0 && rulerRight < moveX) || width / 2 - rulerRight < getWhichScalMovex(maxScale) - moveX) {
                    //当滑动出范围的话,不绘制,去除左右边界
                } else {
                    //绘制小数刻度
                    canvas.drawLine(0, 0, 0, smallScaleHeight, smallScalePaint);
                }
            }
            ++num1;  //刻度加1
            rulerRight += scaleGap;  //绘制屏幕的距离在原有基础上+1个刻度间距
            canvas.translate(scaleGap, 0); //移动画布到下一个刻度
        }

        canvas.restore();
        //绘制屏幕中间用来选中刻度的最大刻度
        canvas.drawLine(width / 2, 0, width / 2, lagScaleHeight, lagScalePaint);

    }

    //绘制上面的结果 结果值+单位
    private void drawResultText(Canvas canvas, String resultText) {
        if (!showScaleResult) {//判断用户是否设置需要显示当前刻度值,如果否则取消绘制
            return;
        }
        if (showScaleResultInteger) {//判断用户是否设置需要显示当前刻度值为整数
            resultText = String.valueOf(Float.valueOf(resultText).intValue());
        }
        canvas.translate(0, -resultNumRect.height() - rulerToResultgap / 2);  //移动画布到正确的位置来绘制结果值
        resultNumPaint.getTextBounds(resultText, 0, resultText.length(), resultNumRect);
        kgPaint.getTextBounds(unit, 0, unit.length(), kgRect);

        float x = width / 2 - (resultNumRect.width() / 2 + kgRect.width() / 2);
        canvas.drawText(resultText, x, resultNumRect.height(), //绘制当前刻度结果值
                resultNumPaint);
        resultNumRight = (int) (x + resultNumRect.width() + 10);
        canvas.drawText(unit, resultNumRight, resultNumRect.height(), kgPaint);//绘制当前刻度结果值单位
    }

    private void drawBg(Canvas canvas) {
        bgRect.set(0, 0, width, height);
        if (isBgRoundRect) {
            canvas.drawRoundRect(bgRect, 20, 20, bgPaint); //20->椭圆的用于圆形角x-radius
        } else {
            canvas.drawRect(bgRect, bgPaint);
        }
    }

    public void computeScrollTo(float scale) {
        scale = scale / scaleLimit;
        if (scale < minScale || scale > maxScale) {
            return;
        }

        computeScale = scale;
        invalidate();

    }

    public interface OnChooseResulterListener {
        void onEndResult(String resultS, float resultF);

        void onScrollResult(String result);
    }

    public void setRulerHeight(int rulerHeight) {
        this.rulerHeight = rulerHeight;
        invalidate();
    }

    public void setRulerToResultgap(int rulerToResultgap) {
        this.rulerToResultgap = rulerToResultgap;
        invalidate();
    }

    public void setScaleCount(int scaleCount) {
        this.scaleCount = scaleCount;
        invalidate();
    }

    public void setScaleGap(int scaleGap) {
        this.scaleGap = scaleGap;
        invalidate();
    }

    public void setMinScale(int minScale) {
        this.minScale = minScale;
        invalidate();
    }

    public void setFirstScale(float firstScale) {
        this.firstScale = firstScale;
        invalidate();
    }

    public float getFirstScale() {
        if (this.firstScale == -1) this.firstScale = currentScale;
        return this.firstScale;
    }

    public void setMaxScale(int maxScale) {
        this.maxScale = maxScale;
        invalidate();
    }

    public void setBgColor(int bgColor) {
        this.bgColor = bgColor;
        invalidate();
    }

    public void setSmallScaleColor(int smallScaleColor) {
        this.smallScaleColor = smallScaleColor;
        invalidate();
    }

    public void setMidScaleColor(int midScaleColor) {
        this.midScaleColor = midScaleColor;
        invalidate();
    }

    public void setLargeScaleColor(int largeScaleColor) {
        this.largeScaleColor = largeScaleColor;
    }

    public void setScaleNumColor(int scaleNumColor) {
        this.scaleNumColor = scaleNumColor;
        invalidate();
    }

    public void setResultNumColor(int resultNumColor) {
        this.resultNumColor = resultNumColor;
        invalidate();
    }

    public void setUnit(String unit) {
        this.unit = unit;
        invalidate();
    }

    public void setUnitColor(int unitColor) {
        this.unitColor = unitColor;
        invalidate();
    }

    public void setSmallScaleStroke(int smallScaleStroke) {
        this.smallScaleStroke = smallScaleStroke;
        invalidate();
    }

    public void setMidScaleStroke(int midScaleStroke) {
        this.midScaleStroke = midScaleStroke;
        invalidate();
    }

    public void setLargeScaleStroke(int largeScaleStroke) {
        this.largeScaleStroke = largeScaleStroke;
        invalidate();
    }

    public void setResultNumTextSize(int resultNumTextSize) {
        this.resultNumTextSize = resultNumTextSize;
        invalidate();
    }

    public void setScaleNumTextSize(int scaleNumTextSize) {
        this.scaleNumTextSize = scaleNumTextSize;
        invalidate();
    }

    public void setUnitTextSize(int unitTextSize) {
        this.unitTextSize = unitTextSize;
        invalidate();
    }

    public void setShowScaleResult(boolean showScaleResult) {
        this.showScaleResult = showScaleResult;
        invalidate();
    }

    public void setShowScaleResultInteger(boolean showScaleResultInteger) {
        this.showScaleResultInteger = showScaleResultInteger;
        invalidate();
    }

    public void setIsBgRoundRect(boolean bgRoundRect) {
        isBgRoundRect = bgRoundRect;
        invalidate();
    }

    public void setScaleLimit(int scaleLimit) {
        this.scaleLimit = scaleLimit;
        invalidate();
    }
}

MainActivity.kt

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var ruleView3 = findViewById<MyRulerView>(R.id.ruleView3)
        ruleView3. setOnChooseResulterListener(object : MyRulerView.OnChooseResulterListener{
            override fun onEndResult(resultS: String?, resultF: Float) {
                //滑动结束时的值
                Log.d("TAG", "onEndResult:$resultS resultF:$resultF ")
            }

            override fun onScrollResult(result: String?) {
                //滑动时的值
                Log.d("TAG", "onScrollResult:$result ")

            }

        } )
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <declare-styleable name="MyRulerView">
        <attr name="rulerHeight" format="dimension" />
        <attr name="rulerToResultgap" format="dimension" />
        <attr name="scaleGap" format="dimension" />
        <attr name="scaleCount" format="integer" />
        <attr name="firstScale" format="float" />
        <attr name="maxScale" format="integer" />
        <attr name="minScale" format="integer" />
        <attr name="bgColor" format="color" />
        <attr name="smallScaleColor" format="color" />
        <attr name="midScaleColor" format="color" />
        <attr name="largeScaleColor" format="color" />
        <attr name="scaleNumColor" format="color" />
        <attr name="resultNumColor" format="color" />
        <attr name="unit" format="string" />
        <attr name="unitColor" format="color" />
        <attr name="smallScaleStroke" format="dimension" />
        <attr name="midScaleStroke" format="dimension" />
        <attr name="largeScaleStroke" format="dimension" />
        <attr name="resultNumTextSize" format="dimension" />
        <attr name="scaleNumTextSize" format="dimension" />
        <attr name="unitTextSize" format="dimension" />
        <attr name="showScaleResult" format="boolean" />
        <attr name="showScaleResultInteger" format="boolean" />
        <attr name="isBgRoundRect" format="boolean" />
        <attr name="scaleLimit" format="integer" />
    </declare-styleable>
</resources>

activity_main.xml文章来源地址https://www.toymoban.com/news/detail-542171.html

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!--原代码-->
    <com.example.myapplication.MyRulerView
        android:id="@+id/ruleView3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:bgColor="#fcfffc"
        app:firstScale="150"
        app:isBgRoundRect="true"
        app:largeScaleColor="#aa50b586"
        app:largeScaleStroke="3dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:maxScale="200"
        app:midScaleColor="#999999"
        app:midScaleStroke="1dp"
        app:minScale="100"
        app:resultNumColor="#50b586"
        app:resultNumTextSize="20sp"
        app:rulerHeight="50dp"
        app:rulerToResultgap="20dp"
        app:scaleCount="10"
        app:scaleGap="10dp"
        app:scaleLimit="1"
        app:scaleNumColor="#666666"
        app:scaleNumTextSize="16sp"
        app:showScaleResult="true"
        app:smallScaleColor="#aaaaaa"
        app:smallScaleStroke="1dp"
        app:unit="CM"
        app:unitColor="#50b586"
        app:unitTextSize="20sp"
        tools:ignore="MissingConstraints" />

    <com.example.myapplication.MyRulerView
        android:id="@+id/ruleView4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:bgColor="#fcfffc"
        app:firstScale="150"
        app:isBgRoundRect="true"
        app:largeScaleColor="#aa50b586"
        app:largeScaleStroke="3dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ruleView3"
        app:maxScale="200"
        app:midScaleColor="#999999"
        app:midScaleStroke="1dp"
        app:minScale="100"
        app:resultNumColor="#50b586"
        app:resultNumTextSize="20sp"
        app:rulerHeight="50dp"
        app:rulerToResultgap="20dp"
        app:scaleCount="10"
        app:scaleGap="10dp"
        app:scaleLimit="1"
        app:scaleNumColor="#666666"
        app:scaleNumTextSize="16sp"
        app:showScaleResult="true"
        app:smallScaleColor="#aaaaaa"
        app:smallScaleStroke="1dp"
        app:unit="CM"
        app:unitColor="#50b586"
        app:unitTextSize="20sp" />

    <com.example.myapplication.MyRulerView
        android:id="@+id/ruleView5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        app:bgColor="#fcfffc"
        app:firstScale="150"
        app:isBgRoundRect="true"
        app:largeScaleColor="#aa50b586"
        app:largeScaleStroke="3dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ruleView4"
        app:maxScale="200"
        app:midScaleColor="#999999"
        app:midScaleStroke="1dp"
        app:minScale="100"
        app:resultNumColor="#50b586"
        app:resultNumTextSize="20sp"
        app:rulerHeight="50dp"
        app:rulerToResultgap="20dp"
        app:scaleCount="10"
        app:scaleGap="10dp"
        app:scaleLimit="10"
        app:scaleNumColor="#666666"
        app:scaleNumTextSize="16sp"
        app:showScaleResult="true"
        app:showScaleResultInteger="true"
        app:smallScaleColor="#aaaaaa"
        app:smallScaleStroke="1dp"
        app:unit="mmol/L"
        app:unitColor="#50b586"
        app:unitTextSize="20sp" />

</androidx.constraintlayout.widget.ConstraintLayout>

到了这里,关于安卓自定义尺子控件RulerView的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android:自定义控件

    1.自定义VIEW组件 创建CustomizeView,继承View。重写onDraw方法,通过onDraw方法绘制我们自定义的图像、位图、路径等。 示例: 创建对应layout文件,l_customize1.xml文件 示例: 补充:Canvas对象坐标变换方法 translate(100,100):平移变化; rotate(90):旋转变化; scale():缩放变化; save():保存当前

    2024年02月20日
    浏览(38)
  • 【Android】自定义Spinner控件及其使用

    在 res/values/ 文件夹下新建一个 arrays.xml 文件: activity_main.xml 文件: 2.1 dropdown模式 效果: 2.2 dialog模式 效果: 在 res/drawable/ 文件夹下新建两个文件: (1) shape_for_custom_spinner.xml 文件(用来定义下拉框的样式): (2) selector_for_custom_spinner 文件(用来定义Spinner控件本身的样

    2023年04月16日
    浏览(35)
  • 【Android控件】HorizontalScrollView的基础使用记录(滚动条自定义)

    目录 ​​​​​​​ 效果图 简介 注意事项 基础属性 滚动条全部设置 滚动条是否总显示 自定义滚动条滑动背景和滚动条背景 设置滚动条的宽度 设置滚动条距离 其它常规设置 设置滚动速度 布局代码示例 总结 HorizontalScrollView是水平滚动标签。垂直滚动动是 ScrollView标签 H

    2024年02月10日
    浏览(44)
  • 使用Winform开发自定义用户控件,以及实现相关自定义事件的处理

    在我们一些非标的用户界面中,我们往往需要自定义用户控件界面,从而实现不同的内容展示和处理规则,本篇内容介绍使用Winform开发自定义用户控件,以及实现相关自定义事件的处理。 对于比较规范的界面,需要进行一定的分析,以便从中找到对应的规则,逐步细化为自

    2024年02月03日
    浏览(46)
  • 使用WPF开发自定义用户控件,以及实现相关自定义事件的处理

    在前面随笔《使用Winform开发自定义用户控件,以及实现相关自定义事件的处理》中介绍了Winform用户自定义控件的处理,对于Winform自定义的用户控件来说,它的呈现方式主要就是基于GDI+进行渲染的,对于数量不多的控件呈现,一般不会觉察性能有太多的问题,随着控件的数量

    2024年02月02日
    浏览(52)
  • flutter开发实战-自定义Switch开关控件Widget

    flutter开发实战-自定义Switch开关控件 在flutter中实现自定义Switch,主要实现类似IOS的UISwitch样式的开关控件 实现自定义Switch的Widget,主要实现交织动画。 交织动画 有些时候我们可能会需要一些复杂的动画,这些动画可能由一个动画序列或重叠的动画组成。一个动画组合在不同

    2024年02月13日
    浏览(50)
  • 安卓Android开发快速入门

    配合天哥视频食用更佳:【天哥】Android开发视频教程最新版 Android Studio开发 LinearLayout(线性布局) 可嵌套 最常用属性 id 起标记布局的作用 layout_width [wrap_content根据内容选择大小、match_parent匹配父级、具体数值(单位-dp)] layout_height layout_weight 权重,按照权重比例分配父级

    2023年04月16日
    浏览(44)
  • android原生开发教程,安卓开发入门到精通

    建造者模式: 观察者模式: 代理模式: 门面模式: 单例模式: 生产者消费者模式: 这个通过对比来描述,比如面向对象和面向过程的对比,针对这两种思想的对比,还可以举个开发中的例子,比如播放器的实现,面向过程的实现方式就是将播放视频的这个功能分解成多个过

    2024年04月11日
    浏览(61)
  • iOS开发-聊天emoji表情与自定义动图表情左右滑动控件

    iOS开发-聊天emoji表情与自定义动图表情左右滑动控件 之前开发中遇到需要实现聊天emoji表情与自定义动图表情左右滑动控件。使用UICollectionView实现。 UICollectionView是一种类似于UITableView但又比UITableView功能更强大、更灵活的视图,这是源于它将UICollectionView对cell的布局交给了

    2024年02月15日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包