前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义View | 仿QQ运动步数进度效果

自定义View | 仿QQ运动步数进度效果

作者头像
凌川江雪
发布2020-09-01 23:33:57
4240
发布2020-09-01 23:33:57
举报
文章被收录于专栏:李蔚蓬的专栏李蔚蓬的专栏

项目GitHub地址

思路

  • 固定不动的蓝色大圆弧
  • 动画变动的红色小圆弧
  • 中间的步数文字显示
  • 相关的自定义属性 比如固定不动的大圆弧 我们不能写死他的蓝色颜色属性, 要提供一个颜色的自定义属性给用户自定义配置 圆弧的宽度也是要可以自定义的;

自定义属性

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<resources>
...
    <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>

布局使用

代码语言:javascript
复制
<com.lwp.customviewtest.CustomViews.QQStepView
        android:id="@+id/step_view"
        app:outerColor="@color/colorPrimary"
        app:innerColor="@color/colorAccent"
        app:borderWidth="15dp"
        app:stepTextColor="@color/colorAccent"
        app:stepTextSize="16sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

自定义View逻辑

代码语言:javascript
复制
public class QQStepView extends View {

    //初始化 自定义属性变量 并给 默认值
    private int mOuterColor = Color.RED;//默认红色
    private int mInnerColor = Color.BLUE;//默认蓝色
    private int mBorderWidth = 20;//20px
    private int mStepTextSize = 20;
    private int mStepTextColor = Color.RED;

    private Paint mPaint;
    private int mStartAngle = 135;
    private int mSweepAngle = 270;

    private int mStepMax = 0;
    private int mCurrentStep = 0;


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

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

    public QQStepView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

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

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setColor(mOuterColor);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 调用者在布局文件中可能是 wrap_content 要做判断

        //获取宽高
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //设置宽高
        // 宽高不一致 取最小值、确保是个正方形
        setMeasuredDimension(widthSize > heightSize ? heightSize : widthSize,
                widthSize > heightSize ? heightSize : widthSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //画外圆弧==============================
        //拿到View的中心点
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        // 半径
        int radius = (int) (centerX - mBorderWidth);
        // 设置圆弧画笔的宽度
        mPaint.setStrokeWidth(mBorderWidth);
        // 设置弧线的 首端 和 尾端 为 圆弧
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        // 设置画笔颜色
        mPaint.setColor(mOuterColor);
        mPaint.setStyle(Paint.Style.STROKE);

        //圆弧 内边缘的弧线的 外切矩形
        RectF oval = new RectF(mBorderWidth, mBorderWidth, centerX + radius, centerY + radius);
        // 画背景圆弧
        canvas.drawArc(oval, mStartAngle, mSweepAngle, false, mPaint);

        //画内圆弧==============================
        // 提供百分比 给用户自己配置 【自定义属性】
        mPaint.setColor(mInnerColor);
        // 计算当前百分比
        float percent = (float) mCurrentStep / mStepMax;
        if (mStepMax != 0) {
            // 根据当前百分比计算圆弧扫描的角度
            canvas.drawArc(oval, mStartAngle, percent * mSweepAngle, false, mPaint);
        }

        //画文字==============================
        // 重置画笔
        mPaint.reset();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(mStepTextSize);
        mPaint.setColor(mStepTextColor);
        //文本内容
//        String mStep = ((int) (percent * mStepMax)) + "";
        String mStep = mCurrentStep + "";
        // 测量文字的宽高
        Rect textBounds = new Rect();
        mPaint.getTextBounds(mStep, 0, mStep.length(), textBounds);
        //文字的x轴起始点
        int dx = (getWidth() - textBounds.width()) / 2;
        // 获取画笔的FontMetrics
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        // 计算文字的基线
        int baseLine = (int) (getHeight() / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom);
        // 绘制步数文字
        canvas.drawText(mStep, dx, baseLine, mPaint);
    }

    // 设置当前最大步数
    public synchronized void setMaxStep(int maxStep) {
        if (maxStep < 0) {
            throw new IllegalArgumentException("max 不能小于0!");
        }
        this.mStepMax = maxStep;
    }
    public synchronized int getMaxStep() {
        return mStepMax;
    }
    // 设置进度
    public synchronized void setProgress(int progress) {
        if (progress < 0) {
            throw new IllegalArgumentException("progress 不能小于0!");
        }
        this.mCurrentStep = progress;
        // 重新刷新绘制 -> onDraw()
        invalidate();
    }
    public synchronized int getProgress() {
        return mCurrentStep;
    }
}

在Activity中使用自定义View和动画

代码语言:javascript
复制
final QQStepView qqStepView = (QQStepView) findViewById(R.id.step_view);
                qqStepView.setMaxStep(6000);

                //属性动画
                ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 5678);
                valueAnimator.setDuration(1000);
                valueAnimator.setInterpolator(new DecelerateInterpolator());
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentStep = (float) animation.getAnimatedValue();
                        qqStepView.setProgress((int)currentStep);
                    }
                });
                valueAnimator.start();
                break;

效果:


参考:自定义View - 仿QQ运动步数进度效果

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 思路
  • 自定义属性
  • 布局使用
  • 自定义View逻辑
  • 在Activity中使用自定义View和动画
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档