红橙Darren视频笔记 仿QQ步数计数view 画笔的使用

步骤

1.自定义属性
2.在xml中使用
3.创建自定义view文件 写好构造函数
4.在上面的Java文件中访问自定义属性
5.实现onMeasure方法
6.画外圆弧 内圆弧 文字
7.添加一点动画

效果图

在这里插入图片描述

新建attrs文件夹 编写自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- step1 定义组定义属性 -->
    <declare-styleable name="QQStepView">
        <attr name="outerColor" format="color"/>
        <attr name="innerColor" format="color"/>
        <attr name="borderWidth" format="dimension"/>
        <attr name="stepTextSize" format="dimension"/>
        <attr name="stepTextColor" format="color"/>
    </declare-styleable>
</resources>

在xml中使用

<?xml version="1.0" encoding="utf-8"?>
<!-- step2 在xml中使用自定义属性 -->
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:chjapp="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <com.example.chj.myapplication.QQStepView
        android:id="@+id/myQQStepView"
        chjapp:stepTextColor="@color/colorAccent"
        chjapp:stepTextSize="30sp"
        chjapp:innerColor="@color/colorAccent"
        chjapp:outerColor="@color/colorPrimary"
        android:background="@android:color/holo_green_light"
        chjapp:borderWidth="15dp"
        android:layout_width="200dp"
        android:layout_height="200dp" />

</android.support.constraint.ConstraintLayout>

编写自定义view

package com.example.chj.myapplication;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

public class QQStepView extends View {
    private int mOuterColor = Color.BLUE;
    private int mInnerColor = Color.GREEN;
    private int mBorderWidth = 1;
    private int mStepTextSize = 5;
    private int mStepTextColor = Color.GRAY;
    private Paint mOuterArcPaint, mInnerArcPaint, mTextPaint;
    private float mStepMax = 8000;
    private float mStepCurrent = 2000;


    //step3 创建java 文件并准备好构造方法
    public QQStepView(Context context) {
        this(context, null);
    }

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

    public QQStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //step4 获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
        mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
        mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
        mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
        mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, mBorderWidth);
        mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, mStepTextSize);
        array.recycle();

        mOuterArcPaint = new Paint();
        mOuterArcPaint.setAntiAlias(true);//抗锯齿
        mOuterArcPaint.setColor(mOuterColor);
        mOuterArcPaint.setStrokeWidth(mBorderWidth);
        mOuterArcPaint.setStyle(Paint.Style.STROKE);//画空心弧
        mOuterArcPaint.setStrokeCap(Paint.Cap.ROUND);//收口(帽子)为圆形 而不是直角

        mInnerArcPaint = new Paint();
        mInnerArcPaint.setAntiAlias(true);//抗锯齿
        mInnerArcPaint.setColor(mInnerColor);
        mInnerArcPaint.setStrokeWidth(mBorderWidth);
        mInnerArcPaint.setStyle(Paint.Style.STROKE);//画空心弧
        mInnerArcPaint.setStrokeCap(Paint.Cap.ROUND);//收口(帽子)为圆形 而不是直角

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);//抗锯齿
        mTextPaint.setColor(mStepTextColor);
        mTextPaint.setTextSize(mStepTextSize);
    }

    //step5 编写onMeasure方法 决定控件宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //如果xml中定义的宽高任意一个是wrap content 给控件一个最小宽高
        int smallerValue = 50;
        if (MeasureSpec.AT_MOST != MeasureSpec.getMode(widthMeasureSpec) && MeasureSpec.AT_MOST != MeasureSpec.getMode(heightMeasureSpec)) {
            //TODO 疑问 如果使用match parent出现的效果不对 不是正方形 但是断点看 应该宽高设置一致了。。。
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            //宽高取最小值 确保是个正方形
            smallerValue = Math.min(width, height);
        }
        setMeasuredDimension(smallerValue, smallerValue);
    }

    //step6 编写onDraw方法 画外圆弧 内圆弧 文字
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //step6.1 绘制外圆弧
        //边缘没有显示完整 是因为描边有宽度 需要减去描边宽度的一半 视频中的计算有些复杂了 不够直接
        RectF rectF = new RectF(mOuterArcPaint.getStrokeWidth() / 2, mOuterArcPaint.getStrokeWidth() / 2, getWidth() - mOuterArcPaint.getStrokeWidth() / 2, getHeight() - mOuterArcPaint.getStrokeWidth() / 2);
        //参数 绘制区域 开始绘制的角度 画笔扫过后绘制的角度 是否封闭 画笔
        canvas.drawArc(rectF, 135, 270, false, mOuterArcPaint);

        if (mStepMax == 0) {
            return;
        }
        //step6.2 绘制内圆弧(当前步数占总步数的比例==内弧的角度占外弧角度的比例)
        float innerArcSweepAngle = (mStepCurrent / mStepMax) * 270;//270是外弧的角度
        canvas.drawArc(rectF, 135, innerArcSweepAngle, false, mInnerArcPaint);

        //step6.3 绘制文字
        String mStepCurrentStr = (int) mStepCurrent + "";

        //计算文字绘制的左边起始点:(控件的宽度-文字的宽度)/2
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(mStepCurrentStr, 0, mStepCurrentStr.length(), textBounds);//用于计算text的宽度
        float textStartX = (getWidth() - textBounds.width()) / 2.0f;

        //计算文字绘制的baseline
        Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
        int baseLine = getHeight() / 2 - fontMetricsInt.bottom / 2 - fontMetricsInt.top / 2;
        //int baseLine = Math.abs((fontMetricsInt.bottom - fontMetricsInt.top - getHeight()) / 2 + fontMetricsInt.top);

        //使用方法drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
        //含义 文本 左边的绘制起始点 baseline 画笔
        canvas.drawText(mStepCurrentStr, textStartX, baseLine, mTextPaint);
    }

    public synchronized void setStepMax(int stepMax) {
        this.mStepMax = stepMax;
    }

    public synchronized void setStepCurrent(int stepCurrent) {
        this.mStepCurrent = stepCurrent;
        //不断绘制
        invalidate();
    }
}

在主界面使用自定义view

package com.example.chj.myapplication;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.animation.DecelerateInterpolator;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final QQStepView qqStepView = findViewById(R.id.myQQStepView);
        qqStepView.setStepMax(20000);

        //step7 添加属性动画
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0,10799);
        valueAnimator.setDuration(1500);
        valueAnimator.setInterpolator(new DecelerateInterpolator());//插值器 用于调整动画播放速度 先快后慢
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep = (float) animation.getAnimatedValue();
                qqStepView.setStepCurrent((int) currentStep);
            }
        });
        valueAnimator.start();
    }

}

代码:
https://github.com/caihuijian/learn_darren_android.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值