美文网首页Android自定义View自定义view
自定义View - 仿QQ运动步数进度效果

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

作者: Peakmain | 来源:发表于2018-07-06 13:45 被阅读3次

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

    效果图.gif

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

    分析.png

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

    基线.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**
    
    ###接下来开始做项目:
    
     - 第一步自定义属性
    一共需要:内部圆环颜色,外部圆环颜色,圆环宽度,文字颜色,文字大小五种
    
    

    <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>

    
     - 自定义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运动步数进度效果

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