美文网首页
自定义view(四)----自定义进度view

自定义view(四)----自定义进度view

作者: 会写代码的小猿猴 | 来源:发表于2022-02-17 14:38 被阅读0次

    本文主演参照前一篇文章打造了一个自定义的进度条,仅作代码记录。
    实现效果:


    1645079823700.gif

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="ProcessBarView">
            <attr name="innerColor" format="color"/>
            <attr name="outerColor" format="color"/>
            <attr name="borderWidth" format="dimension"/>
            <attr name="NumTextColor" format="color"/>
            <attr name="NumTextSize" format="dimension"/>
        </declare-styleable>
    </resources>
    

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <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.view04.ProcessBarView
            app:NumTextSize="22sp"
            app:outerColor="#C0C0C0"
            android:id="@+id/processBarView"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <Button
            android:text="开始"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="startAnimator"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/processBarView"
            tools:ignore="OnClick" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
        private ProcessBarView mProcessView;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mProcessView=findViewById(R.id.processBarView);
    
        }
        public void startAnimator(View view){
            mProcessView.setSweepAngle(0);
            ValueAnimator valueAnimator= ObjectAnimator.ofFloat(0,100);
            valueAnimator.setDuration(10000);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
    
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float mSweepAngle= (float) animation.getAnimatedValue();
                    //保留两位小数
                    BigDecimal b = new BigDecimal(mSweepAngle);
                    double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                    mProcessView.setSweepAngle((float) f1);
                }
            });
            valueAnimator.start();
        }
    }
    

    ProcessBarView.java

    public class ProcessBarView extends View {
        private Context mContext;
        private int mOutColor;
        private int mInnerColor;
        private int mBorderWidth;
        private int mNumTextSize;
        private int mNumTextColor;
        private Paint mOutPaint;
        private Paint mInnerPaint;
        private Paint mTextPaint;
    
    
    
        private float mSweepAngle=0;
        private int mMaxAngle=100;
    
        public ProcessBarView(Context context) {
            this(context, null);
        }
    
        public ProcessBarView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ProcessBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProcessBarView);
            mOutColor = typedArray.getColor(R.styleable.ProcessBarView_outerColor, Color.RED);
            mInnerColor = typedArray.getColor(R.styleable.ProcessBarView_innerColor, Color.BLUE);
            mBorderWidth = (int) typedArray.getDimension(R.styleable.ProcessBarView_borderWidth, 20);
            mNumTextColor = typedArray.getColor(R.styleable.ProcessBarView_NumTextColor, Color.RED);
            mNumTextSize = typedArray.getDimensionPixelSize(R.styleable.ProcessBarView_NumTextSize, 20);
    
            mOutPaint=new Paint();
            mOutPaint.setAntiAlias(true);
            mOutPaint.setStrokeWidth(mBorderWidth);
            mOutPaint.setColor(mOutColor);
            mOutPaint.setStyle(Paint.Style.STROKE);
            mOutPaint.setStrokeCap(Paint.Cap.ROUND);
    
            mInnerPaint=new Paint();
            mInnerPaint.setAntiAlias(true);
            mInnerPaint.setStrokeWidth(mBorderWidth);
            mInnerPaint.setColor(mInnerColor);
            mInnerPaint.setStyle(Paint.Style.STROKE);
            mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
    
            mTextPaint=new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(mNumTextColor);
            mTextPaint.setTextSize(mNumTextSize);
    
            typedArray.recycle();
        }
    
        public ProcessBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            mContext=context;
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            setMeasuredDimension(widthSize > heightSize ? heightSize : widthSize, widthSize > heightSize ? heightSize : widthSize);
        }
    
        @Override
        public void draw(Canvas canvas) {
            //画外圆
            super.draw(canvas);
            RectF rectf=new RectF(50,50,getWidth()-2*mBorderWidth,getHeight()-2*mBorderWidth);
            canvas.drawArc(rectf,0,360,false,mOutPaint);
            //画内圆
            canvas.drawArc(rectf,0,mSweepAngle/mMaxAngle*360,false,mInnerPaint);
            //画文字
            String stepText = mSweepAngle+"%";
            Rect textBounds = new Rect();
            mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);//测量文字画笔长度
            int dx = getWidth() / 2 - textBounds.width() / 2;
            Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
            int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
            int baseLine = getHeight() / 2 + dy;
            canvas.drawText(stepText, dx, baseLine, mTextPaint);
        }
        public void setSweepAngle(float sweepAngle){
            this.mSweepAngle=sweepAngle;
            invalidate();
        }
    }
    

    下面是两个类的kotlin代码实现:
    MainActivity

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            start.setOnClickListener { startAnimator() }
        }
    
        private fun startAnimator() {
            processBarView!!.setSweepAngle(0.00)
            val valueAnimator = ObjectAnimator.ofFloat(0f, 100f)
            valueAnimator.duration = 10000
            valueAnimator.addUpdateListener { animation ->
                val mSweepAngle = animation.animatedValue
                //保留两位小数
                val b: BigDecimal = BigDecimal(mSweepAngle.toString())
                val f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).toDouble()
                processBarView!!.setSweepAngle(f1)
            }
            valueAnimator.start()
        }
    }
    

    ProcessBarView

    class ProcessBarView : View {
        private var mContext: Context? = null
        private var mOutColor = 0
        private var mInnerColor = 0
        private var mBorderWidth = 0
        private var mNumTextSize = 0
        private var mNumTextColor = 0
        private var mOutPaint: Paint? = null
        private var mInnerPaint: Paint? = null
        private var mTextPaint: Paint? = null
        private var mSweepAngle = 0.00
        private val mMaxAngle = 100
    
        @JvmOverloads
        constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : super(
            context,
            attrs,
            defStyleAttr
        ) {
            val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProcessBarView)
            mOutColor = typedArray.getColor(R.styleable.ProcessBarView_outerColor, Color.RED)
            mInnerColor = typedArray.getColor(R.styleable.ProcessBarView_innerColor, Color.BLUE)
            mBorderWidth = typedArray.getDimension(R.styleable.ProcessBarView_borderWidth, 20f).toInt()
            mNumTextColor = typedArray.getColor(R.styleable.ProcessBarView_NumTextColor, Color.RED)
            mNumTextSize = typedArray.getDimensionPixelSize(R.styleable.ProcessBarView_NumTextSize, 20)
            mOutPaint = Paint()
            mOutPaint!!.isAntiAlias = true
            mOutPaint!!.strokeWidth = mBorderWidth.toFloat()
            mOutPaint!!.color = mOutColor
            mOutPaint!!.style = Paint.Style.STROKE //该属性代表非实心圆
            mOutPaint!!.strokeCap = Paint.Cap.ROUND
    
            mInnerPaint = Paint()
            mInnerPaint!!.isAntiAlias = true
            mInnerPaint!!.strokeWidth = mBorderWidth.toFloat()
            mInnerPaint!!.color = mInnerColor
            mInnerPaint!!.style = Paint.Style.STROKE
            mInnerPaint!!.strokeCap = Paint.Cap.ROUND
    
            mTextPaint = Paint()
            mTextPaint!!.isAntiAlias = true
            mTextPaint!!.color = mNumTextColor
            mTextPaint!!.textSize = mNumTextSize.toFloat()
            typedArray.recycle()
        }
    
        constructor(
            context: Context?,
            attrs: AttributeSet?,
            defStyleAttr: Int,
            defStyleRes: Int
        ) : super(context, attrs, defStyleAttr, defStyleRes) {
            mContext = context
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            val widthSize = MeasureSpec.getSize(widthMeasureSpec)
            val heightSize = MeasureSpec.getSize(heightMeasureSpec)
            setMeasuredDimension(widthSize.coerceAtMost(heightSize), widthSize.coerceAtMost(heightSize))
        }
    
        override fun draw(canvas: Canvas) {
            //画外圆
            super.draw(canvas)
            val rectf = RectF(
                50F,
                50F,
                (width - 2 * mBorderWidth).toFloat(),
                (height - 2 * mBorderWidth).toFloat()
            )
            canvas.drawArc(rectf, 0f, 360f, false, mOutPaint!!)
            //画内圆
            canvas.drawArc(rectf, 0f, (mSweepAngle / mMaxAngle * 360).toFloat(), false, mInnerPaint!!)
            //画文字
            val stepText = "$mSweepAngle%"
            val textBounds = Rect()
            mTextPaint!!.getTextBounds(stepText, 0, stepText.length, textBounds) //测量文字画笔长度
            val dx = width / 2 - textBounds.width() / 2
            val fontMetricsInt = mTextPaint!!.fontMetricsInt
            val dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom
            val baseLine = height / 2 + dy
            canvas.drawText(stepText, dx.toFloat(), baseLine.toFloat(), mTextPaint!!)
        }
    
        fun setSweepAngle(sweepAngle: Double) {
            mSweepAngle = sweepAngle
            invalidate()
        }
    }
    

    使用kotlin代码时,别忘了在app目录下的build.gradle中添加插件

    id 'kotlin-android-extensions'
    

    相关文章

      网友评论

          本文标题:自定义view(四)----自定义进度view

          本文链接:https://www.haomeiwen.com/subject/yyhslrtx.html