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

我blog也写过,欢迎各位看我博客,https://blog.csdn.net/qq_24675479
首先看下效果图

自定义View - 仿QQ运动步数进度效果_第1张图片
效果图.gif

在做这个项目之前先了解下文字获取
我上一篇 自定义View入门 - 自定义TextView 有写过——https://www.jianshu.com/p/7b5e4f5abb74

自定义View - 仿QQ运动步数进度效果_第2张图片
分析.png

今天详细讲解一下baseLine 基线(参考文章:文淑大神的自定义View之绘图篇(四)http://blog.csdn.net/u012551350/article/details/51361778)
FontMetrics

自定义View - 仿QQ运动步数进度效果_第3张图片
基线.png

top:可绘制的最高高度所在线
bottom:可绘制的最低高度所在线
ascent :系统建议的,绘制单个字符时,字符应当的最高高度所在线
descent:系统建议的,绘制单个字符时,字符应当的最低高度所在线

获取实例

Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
Paint.FontMetricsInt fm=  mPaint.getFontMetricsInt();

成员变量

        float ascent = fontMetrics.ascent;
        float descent = fontMetrics.descent;
        float top = fontMetrics.top;
        float bottom = fontMetrics.bottom;
        float leading = fontMetrics.leading;

这里的ascent,descent,top,bottom,leading指的是到基线baseline的位置

[图片上传失败...(image-4386fb-1530855738868)]

文字的高度

         float top = fontMetrics.top + baseLineY;
        float bottom = fontMetrics.bottom + baseLineY;
        //文字高度
        float height= bottom - top; //注意top为负数
        //文字中点y坐标
        float center = (bottom - top) / 2;

即中线是(bottom-top)/2,实际呢是bottom+top只是因为这里的top是负的(图片上的top到baseline的距离)

已知中线求baseline
[图片上传失败...(image-9ea4bc-1530855738868)]
结论
baseline=centerY+A-fm.bottom;

centerY呢实际就是getHeight/2,整体高度的一半,然后求基线的y坐标,实际就是(top-bottom)/2-fontMetrics.bottom;再次强调:这里的ascent,descent,top,bottom,leading指的是到基线baseline的位置。最后相加getHeight+(top-bottom)/2-fontMetrics.bottom**

接下来开始做项目:

  • 第一步自定义属性
    一共需要:内部圆环颜色,外部圆环颜色,圆环宽度,文字颜色,文字大小五种

        
        
        
        
        
    
  • 自定义view获取属性,设置属性等
public class QQStepView extends View {
    private int mOuterColor = Color.RED;
    private int mInnerColor = Color.BLUE;
    private int mBorderWidth = 20;
    private int mStepTextSize;
    private int mStepTextColor;
    private Paint mOuterPaint, mInnerPaint, mTextPaint;
    private int mStepMax;//总的步数
    private int mCurrentStep;//当前步数

    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 ta = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
        mOuterColor = ta.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
        mInnerColor = ta.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
        mBorderWidth = (int) ta.getDimension(R.styleable.QQStepView_borderWidth, mBorderWidth);
        mStepTextSize = ta.getDimensionPixelOffset(R.styleable.QQStepView_stepTextSize, mStepTextSize);
        mStepTextColor = ta.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
        ta.recycle();
        //内弧
        mOuterPaint = new Paint();
        mOuterPaint.setAntiAlias(true);
        mOuterPaint.setStrokeWidth(mBorderWidth);
        mOuterPaint.setColor(mOuterColor);
        mOuterPaint.setStrokeCap(Paint.Cap.ROUND);//设置下方为圆形
        mOuterPaint.setStyle(Paint.Style.STROKE);//设置内部为空心
        //外弧
        mInnerPaint = new Paint();
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setStrokeWidth(mBorderWidth);
        mInnerPaint.setColor(mInnerColor);
        mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//设置下方为圆形
        mInnerPaint.setStyle(Paint.Style.STROKE);//设置内部为空心

        //文字
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(mStepTextSize);
        mTextPaint.setColor(mStepTextColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //调用者在布局文件中可能 wrap_content导致宽高不一致
        //确保是正方形
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width > height ? height : width, width > height ? height : width);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //1.画外圆弧   边缘没有显示完整
        //RectF recf = new RectF(0, 0, getWidth(), getHeight());

        int center = getWidth() / 2;
        int radius = getWidth() / 2 - mBorderWidth / 2;
        //mBorderWidth/2,mBorderWidth/2,getWidth()-mBorderWidth/2,getWidth()-mBorderWidth/2
        RectF recf = new RectF(center - radius,
                center - radius,
                center + radius,
                center + radius);
        canvas.drawArc(recf, 135, 270, false, mOuterPaint);
        //2.绘制内圆弧
        float sweepAngle = (float) mCurrentStep / mStepMax;
        canvas.drawArc(recf, 135, sweepAngle * 270, false, mInnerPaint);

        //3.绘制文字
        String stepText = mCurrentStep + "";
        Rect rect = new Rect();
        mTextPaint.getTextBounds(stepText,0,stepText.length(),rect);
        int dx = getWidth() / 2 - rect.width() / 2;
        //第一种方式获取高度
        //int dy = getWidth() / 2 + rect.width()/2;
        //第二种表达方式获取高度
        Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
        //获取中心(fontMetrics.bottom - fontMetrics.top) / 2
        int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        int baseLine = getHeight() / 2 + dy;
        canvas.drawText(stepText, dx, baseLine, mTextPaint);

    }
    //其他,写几个方法让他动起来

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

    public void setCurrentStep(int mCurrentStep) {
        this.mCurrentStep = mCurrentStep;
        //不断绘制 onDraw()
        invalidate();
    }
}

在MainActivity中设置动画

final QQStepView qqStepView = (QQStepView) findViewById(R.id.step_view);
        qqStepView.setStepMax(5000);
        //属性动画
        ValueAnimator animator = ValueAnimator.ofFloat(0, 3000);//0到3000的变化
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep = (float) animation.getAnimatedValue();//获取当前值
                qqStepView.setCurrentStep((int) currentStep);
            }
        });
        animator.setDuration(2000);
        animator.start();

你可能感兴趣的:(自定义View - 仿QQ运动步数进度效果)