欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

QQ运动步数&自定义ProgressBar

程序员文章站 2022-03-24 17:55:01
效果如下 gif图展示效果不好,实际体验无卡顿 1.自定义属性 早Values目录下New values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml) 自定义属性如下,注意format不要与Android自带的命名重复。 2.编写自定义View 3 ......

效果如下

gif图展示效果不好,实际体验无卡顿
QQ运动步数&自定义ProgressBar

1.自定义属性

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

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

    <declare-styleable name="myprogressbar">
        <attr name="leftcolor" format="color" />
        <attr name="rightcolor" format="color" />
        <attr name="progresstextcolor" format="color" />
        <attr name="progresstextsize" format="dimension" />
        <attr name="progressbounds" format="dimension" />
    </declare-styleable>
</resources>
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中使用我们的自定义布局和自定义属性

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="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:orientation="vertical"
    tools:context=".page3.qqsportactivity">

    <com.cyq.customview2.page3.qqstepview
        android:id="@+id/custom_qq_step"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"
        android:layout_margintop="50dp"
        app:borderwidth="6dp"
        app:innercolor="@color/innercolor"
        app:outercolor="@color/outercolor"
        app:steptextsize="30sp"
        android:layout_marginbottom="100dp"/>

    <com.cyq.customview2.page3.myprogressbar
        android:id="@+id/custom_progressbar"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_margin="50dp"
        app:leftcolor="@color/innercolor"
        app:progresstextcolor="@color/steptextcolor"
        app:progresstextsize="16sp"
        app:rightcolor="@color/greycolor" />
</linearlayout>

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

  
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%时不向右边移动,并且文字和进度重叠部分动态变色