资讯专栏INFORMATION COLUMN

QQ运动步数&自定义ProgressBar

plokmju88 / 1285人阅读

摘要:效果如下图展示效果不好,实际体验无卡顿自定义属性早目录下,命名为命名随意,但规范命名为自定义属性如下,注意不要与自带的命名重复。

效果如下

gif图展示效果不好,实际体验无卡顿

1.自定义属性

早Values目录下New-values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml)
自定义属性如下,注意format不要与Android自带的命名重复。



    
        
        
        
        
        
    

    
        
        
        
        
        
    
2.编写自定义View
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;

import com.cyq.customview2.R;
import com.cyq.customview2.utils.MeasureUtils;

@SuppressWarnings("all")
public class QQStepView extends View {
    private int mOuterColor = Color.parseColor("#2196F3");
    private int mInnerColor = Color.parseColor("#F44336");
    private int mStepTextColor = Color.parseColor("#EC407A");
    private int mBorderWidth = 20;//px
    private int mStepTextSize = 18;//px

    private int mSeptMax = 10000;
    private int mSeptCurrent = 0;

    private Paint mOutPaint;
    private Paint mInnerPaint;
    private Paint mTextPaint;

    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);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
        mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
        mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
        mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
        mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, MeasureUtils.dp2px(mBorderWidth, this));
        mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, MeasureUtils.sp2px(mStepTextSize, this));
        array.recycle();

        mOutPaint = new Paint();
        mOutPaint.setAntiAlias(true);
        mOutPaint.setStrokeWidth(mBorderWidth);
        mOutPaint.setColor(mOuterColor);
        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.setStyle(Paint.Style.STROKE);
        mTextPaint.setColor(mStepTextColor);
        mTextPaint.setTextSize(mStepTextSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            //用户设置的是wrap_content,此时设置一个默认宽高100
            width = height = MeasureUtils.dp2px(200, this);
        }
        setMeasuredDimension(width > height ? height : width, width > height ? height : width);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int center = getWidth() / 2;
        int radius = getWidth() / 2 - mBorderWidth;
        RectF rectF = new RectF(mBorderWidth, mBorderWidth, center + radius, center + radius);
        canvas.drawArc(rectF, 135, 270, false, mOutPaint);

        if (mSeptMax == 0) return;
        float sweepAngle = (float) mSeptCurrent / mSeptMax;
        canvas.drawArc(rectF, 135, 270 * sweepAngle, false, mInnerPaint);

        String stepText = mSeptCurrent + "";
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
        int dx = getWidth() / 2 - textBounds.width() / 2;
        int baseLine = MeasureUtils.measureBaseLine(mTextPaint, stepText, this);
        canvas.drawText(stepText, dx, baseLine, mTextPaint);
    }

    public void setmSeptMax(int mSeptMax) {
        this.mSeptMax = mSeptMax;
    }

    public synchronized void setmSeptCurrent(int mSeptCurrent) {
        this.mSeptCurrent = mSeptCurrent;
        //重绘
        invalidate();
    }
}
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;

import com.cyq.customview2.R;
import com.cyq.customview2.utils.MeasureUtils;

@SuppressWarnings("all")
public class MyProgressBar extends View {
    private int mLiftColor = Color.parseColor("#F44336");
    private int mRightColor = Color.parseColor("#E0E0E0");
    private int mProgressTextColor = Color.parseColor("#616161");
    private int mProgressTextSize = 12;//px 后续再考虑需不需要转换成sp
    private int mProgressBounds = 1;//px

    private int mCurrentProgress, mMaxProgress = 100;//默认最大刻度为100

    private Paint mLeftPaint, mRightPaint, mTextPaint;

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

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

    public MyProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar);
        mLiftColor = array.getColor(R.styleable.MyProgressBar_leftColor, mLiftColor);
        mRightColor = array.getColor(R.styleable.MyProgressBar_rightColor, mRightColor);
        mProgressTextColor = array.getColor(R.styleable.MyProgressBar_progressTextColor, mProgressTextColor);
        mProgressTextSize = array.getDimensionPixelSize(R.styleable.MyProgressBar_progressTextSize, mProgressTextSize);
        array.recycle();


        mLeftPaint = new Paint();
        mLeftPaint.setAntiAlias(true);
        mLeftPaint.setColor(mLiftColor);

        mRightPaint = new Paint();
        mRightPaint.setAntiAlias(true);
        mRightPaint.setColor(mRightColor);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.STROKE);
        mTextPaint.setColor(mProgressTextColor);
        mTextPaint.setTextSize(mProgressTextSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widht = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widht, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mRightPaint.setStrokeWidth(getHeight());
        RectF rightRect = new RectF(0, 0, getWidth(), getHeight());
        canvas.drawRoundRect(rightRect, getHeight() / 2, getHeight() / 2, mRightPaint);

        mLeftPaint.setStrokeWidth(getHeight());
        float progress = (float) mCurrentProgress / (mMaxProgress * 10);
        int radius = getHeight() / 2;
        RectF rectF = new RectF(0, 0, progress * getWidth(), getHeight());
        canvas.drawRoundRect(rectF, radius, radius, mLeftPaint);

        //画文字随着进度条右移
        String text = (float) mCurrentProgress / 10 + "%";
        int dx = getHeight() / 2;
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(text, 0, text.length(), textBounds);
        int baseLine = MeasureUtils.measureBaseLine(mTextPaint, text, this);
        canvas.drawText(text, progress * getWidth() + 10, baseLine, mTextPaint);
    }

    public void setProgress(int mCurrentProgress) {
        this.mCurrentProgress = mCurrentProgress;
        //重绘
        invalidate();
    }

    public void setMaxProgress(int mMaxProgress) {
        this.mMaxProgress = mMaxProgress;
    }

    public int getProgress() {
        return mCurrentProgress;
    }
}
3.为自定义View添加动画

首先在xml中使用我们的自定义布局和自定义属性




    

    

通过属性动画动态增加进度

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

import com.cyq.customview2.R;

import butterknife.BindView;
import butterknife.ButterKnife;

public class QQSportActivity extends AppCompatActivity {
    @BindView(R.id.custom_QQ_step)
    QQStepView customQQStep;
    @BindView(R.id.custom_progressbar)
    MyProgressBar customProgressbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qqsport);
        ButterKnife.bind(this);

        customQQStep.setmSeptMax(10000);

        //属性动画
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 8765);
        valueAnimator.setDuration(2000);
        valueAnimator.setInterpolator(new DecelerateInterpolator());//插值器
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep = (Float) animation.getAnimatedValue();
                customQQStep.setmSeptCurrent((int) currentStep);
            }
        });
        valueAnimator.start();

        //属性动画
        ValueAnimator valueAnimator2 = ObjectAnimator.ofFloat(0, 780);
        valueAnimator2.setDuration(2000);
        valueAnimator2.setInterpolator(new DecelerateInterpolator());//插值器
        valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep = (Float) animation.getAnimatedValue();
                customProgressbar.setProgress((int) currentStep);
            }
        });
        valueAnimator2.start();
    }
}

获取文字基线和sp,dp转xp的工具类如下;

import android.graphics.Paint;
import android.graphics.Rect;
import android.util.TypedValue;
import android.view.View;

public class MeasureUtils {
    /**
     * drawText获取基线
     *
     * @param textPaint
     * @param text
     * @param view
     * @return
     */
    public static int measureBaseLine(Paint textPaint, String text, View view) {
        Rect textBounds = new Rect();
        textPaint.getTextBounds(text, 0, text.length(), textBounds);
        Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        int baseLine = view.getHeight() / 2 + dy;
        return baseLine;
    }

    public static int sp2px(int sp, View view) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, view.getResources().getDisplayMetrics());
    }

    public static int dp2px(int dp, View view) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, view.getResources().getDisplayMetrics());
    }
}

后续待改进

1.sp,dp,xp的转换
2.进度文字接近100%时不向右边移动,并且文字和进度重叠部分动态变色

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/2831.html

相关文章

  • 微信小程序实现运动步数排名与发布个人动态&服务器部署

    摘要:项目规划本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内与个人动态的发布,小程序前端采用原生框架,后端采用基于的框架,数据库采用,对象存储采用七牛云,服务器采用阿里,域名采用认证。 1. 项目规划 本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内PK与个人动态的发布,小程序前端采用原生框架,后端采用基于Node的koa2框架,...

    ytwman 评论0 收藏0
  • 微信小程序实现运动步数排名与发布个人动态&服务器部署

    摘要:项目规划本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内与个人动态的发布,小程序前端采用原生框架,后端采用基于的框架,数据库采用,对象存储采用七牛云,服务器采用阿里,域名采用认证。 1. 项目规划 本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内PK与个人动态的发布,小程序前端采用原生框架,后端采用基于Node的koa2框架,...

    laoLiueizo 评论0 收藏0
  • 定义控件及效果

    摘要:实现炫酷的登录效果美观,动画效果丰富风格底部选择器支持时间,日期,自定义带来一组风格底部选择器控件,虽然我们不提倡安卓使用风格的控件,但是难免有些产品和美工一味追求风格。 Android 动画效果定值范围选择控件 实现固定值的范围选择, 并添加动态效果, 使用方便 项目需求讨论 - Android 自定义 Dialog 实现步骤及封装 根据实际项目需求出发。因为项目中的对话框要配合整个...

    刘德刚 评论0 收藏0
  • 卷积编码

    摘要:卷积满足交换操作,因此在一般的维空间输入,自编码可以被用来训练解码编码。事实上,解码卷积的超参数是由编码框架确定的由于卷积跨越每个特征图,并且产生具有的维度,因此经过滤波器之后产生相同的空间范围。 作者:chen_h微信号 & QQ:862251340微信公众号:coderpai简书地址:https://www.jianshu.com/p/ec4... 这篇教程是翻译Paolo Ga...

    shiyang6017 评论0 收藏0
  • 简易仿ios菊花加载loading图

    摘要:原文链接项目中经常会用到加载数据的显示图,除了设计根据自身设计的动画,一般用的比较多的是仿照的菊花加载图,当然一些条件下还会涉及到加载成功失败情况的显示,还有显示文字。使用来加载动画转圈,这里使用文件定义转圈动画,属性进行加载。 原文链接:https://mp.weixin.qq.com/s/wBbQgOfr59wntNK9ZJ5iRw 项目中经常会用到加载数据的loading显示图...

    崔晓明 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<