android 开发 View _16 自定义计步器View、自定义柱状图View


/**
 *@content:实现计步的环形View
 *@time:2018-7-30
 *@build:
 */

public class CountStepsAnnularView extends View {
    private final String TAG = "CountStepsAnnularView";
    //文字组
    private String mAimText;
    private float mAimNum;//目标步数
    private String mStepText;
    private float mCurrentNum;//当前步数
    //参数组
    private float mPadding;//内边距
    private float mOuterRaceWidth;//外环宽度
    private float mInnerRaceWidth;//内环宽度
    private Paint mPaint;
    private Path mPath;
    //颜色组
    private int mAimTextColor;
    private int mCurrenStepNumColor;
    private int mStepTextColor;
    private int[] mOuterRaceColors;
    private float [] mOuterRaceColorPositions;
    private int[] mInnerRaceColors;
    private float [] mInnerRaceColorsPositions;
    //rect



    //动画变量值
    private int animation_innerRace;
    private int animation_currentStep;
    private boolean mStartAnimation;


    public CountStepsAnnularView(Context context) {
        super(context);
        init();

    }

    public CountStepsAnnularView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();

    }

    public CountStepsAnnularView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();

    }
    /**
     * 添加数据的方法
     * @param setAimText ”目标“的文字
     * @param setStepText “步” 的文字
     * @param setAimStepNum 目标步数
     * @param setCurrenStepNum 当前步数
     * @param aimTextColor 目标文字颜色
     * @param currenStepNumColor 当前步数文字颜色
     * @param stepTextColor 步的显示颜色
     * @param startAnimation 是否启用动画
     */
    public void setData(String setAimText,String setStepText,float setAimStepNum,float setCurrenStepNum,
                        int aimTextColor,int currenStepNumColor,int stepTextColor,boolean startAnimation){
        this.mAimText = setAimText;//设置目标文字
        this.mStepText = setStepText;//设置步文字animation_innerRace
        this.mAimNum = setAimStepNum;//设置目标步数
        this.mCurrentNum = setCurrenStepNum;//设置当前步数
        animation_innerRace = 0;
        animation_currentStep = 0 ;
        if(aimTextColor != 0){
            this.mAimTextColor = aimTextColor;
        }else {
            mAimTextColor = 0xF0111111;
        }
        if(currenStepNumColor != 0){
            this.mCurrenStepNumColor = currenStepNumColor;
        }else {
            mCurrenStepNumColor = 0xF0111111;
        }
        if(stepTextColor != 0){
            this.mStepTextColor = stepTextColor;
        }else {
            mStepTextColor = 0xF0111111;
        }
        this.mStartAnimation = startAnimation;
    }

    /**
     * 设置颜色的方法
     * @param outerRaceColors 外环颜色组 例如: int [] colors = new int[]{0xff56F9D0,0xFF4194F9};
     * @param outerRaceColorsPositions 外环颜色渐变点 例如: float [] floats = new float[]{0,0.5f};
     * @param innerRaceColors 内环颜色组
     * @param innerRaceColorspPositions 内环颜色渐变点
     * @ps 颜色组和渐变点组 数量需要一致
     */
    public void setGradientColors(int [] outerRaceColors,float [] outerRaceColorsPositions,
                                  int [] innerRaceColors,float[] innerRaceColorspPositions){
        this.mOuterRaceColors = outerRaceColors;
        this.mOuterRaceColorPositions = outerRaceColorsPositions;
        this.mInnerRaceColors = innerRaceColors;
        this.mInnerRaceColorsPositions = innerRaceColorspPositions;

    }



    private void init(){
        mPaint = new Paint();
        mPath = new Path();

    }
    private void initData(){
        mOuterRaceWidth = getWidth()/10;
        mPadding = mOuterRaceWidth/2+5;
        mInnerRaceWidth = mOuterRaceWidth - 3;
        if(mOuterRaceColors == null){
            mOuterRaceColors = new int[]{0xff56F9D0,0xFF4194F9};
            mOuterRaceColorPositions = new float[]{0,0.5f};
        }
        if(mInnerRaceColors == null){
            mInnerRaceColors = new int[]{0xFF8EF9BE,0xFF26FCB1};
            mInnerRaceColorsPositions = new float[]{0,0.5f};
        }
    }

    //画外环
    private void outerRace(Canvas canvas){
        mPaint.reset();
        mPath.reset();
        //setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mOuterRaceWidth);
        mPaint.setStyle(Paint.Style.STROKE);
        SweepGradient sg = new SweepGradient(getWidth()/2,getHeight()/2,mOuterRaceColors,mOuterRaceColorPositions);
        Matrix matrix = new Matrix();
        matrix.preRotate(135,getWidth(),getHeight());
        sg.setLocalMatrix(matrix);
        mPaint.setShader(sg);
        RectF rectF = new RectF();
        rectF.left = mPadding;
        rectF.top = mPadding;
        rectF.right = getWidth()-mPadding;
        rectF.bottom = getHeight()-mPadding;
        mPath.addArc(rectF,135,270);
        canvas.drawPath(mPath,mPaint);
    }

    //画内环
    private void innerRace(Canvas canvas){
        mPaint.reset();
        mPath.reset();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mInnerRaceWidth);
        mPaint.setStyle(Paint.Style.STROKE);
        SweepGradient sg = new SweepGradient(getWidth()/2,getHeight()/2,mInnerRaceColors,mInnerRaceColorsPositions);
        Matrix matrix = new Matrix();
        matrix.preRotate(135,getWidth(),getHeight());
        sg.setLocalMatrix(matrix);
        mPaint.setShader(sg);
        RectF rectF = new RectF();
        rectF.left = mPadding;
        rectF.top = mPadding;
        rectF.right = getWidth() - mPadding;
        rectF.bottom = getHeight() - mPadding ;
        float currentNum = (float) 270 * (mCurrentNum / mAimNum);
        if(mStartAnimation) {
            //270度是内环最大值,不可以超过270
            if (mCurrentNum > mAimNum) {
                if(animation_innerRace < 270){
                    animation_innerRace = animation_innerRace + 5;
                }
                mPath.addArc(rectF, 135, animation_innerRace);
            } else {

                if (animation_innerRace < currentNum) {
                    animation_innerRace = animation_innerRace + 5;
                }
                mPath.addArc(rectF, 135, animation_innerRace);
            }
        }else {
            //270度是内环最大值,不可以超过270
            if (mCurrentNum > mAimNum) {
                mPath.addArc(rectF, 135, 270);
            } else {
                mPath.addArc(rectF, 135, currentNum);
            }
        }
        canvas.drawPath(mPath,mPaint);
    }

    //目标文字
    private void titleText(Canvas canvas){
        mPath.reset();
        mPaint.reset();
        String aimNumText = Integer.toString((int)mAimNum);
        int num = aimNumText.length()+mAimText.length()+mStepText.length()+1;
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(mAimTextColor);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(getWidth()/100);
        if(num < 10){
            mPaint.setTextSize(getWidth()/10);
        }else {
            mPaint.setTextSize(getWidth()/(num)+2);
        }
        float y = getHeight()/2 - mPadding ;
        float x = getWidth()/2;
        canvas.drawText(mAimText+" "+aimNumText+mStepText,x,y,mPaint);

    }

    //当前数字
    private void currentNumText(Canvas canvas){
        mPath.reset();
        mPaint.reset();
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(mCurrenStepNumColor);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(getWidth()/100);
        mPaint.setTextSize(getWidth()/5);
        float y = getHeight()/2+getWidth()/10+mPadding;
        float x = getWidth()/2;
        if(mStartAnimation) {
            if (animation_currentStep < mCurrentNum) {
                if (mCurrentNum < 300) {
                    animation_currentStep++;
                } else {
                    if (animation_currentStep < mCurrentNum - 500) {
                        animation_currentStep = animation_currentStep + 300;
                    }else if(animation_currentStep < mCurrentNum - 301){
                        animation_currentStep = animation_currentStep + 50;
                    }else if(animation_currentStep < mCurrentNum -51){
                        animation_currentStep = animation_currentStep + 20;
                    }else if (animation_currentStep < mCurrentNum -11){
                        animation_currentStep = animation_currentStep + 5;
                    }else if (animation_currentStep < mCurrentNum){
                        animation_currentStep = animation_currentStep + 1;
                    }
                }
            }
            canvas.drawText(Integer.toString((int) animation_currentStep), x, y, mPaint);
        }else {
            canvas.drawText(Integer.toString((int) mCurrentNum), x, y, mPaint);
        }
    }

    //步文字
    private void stepText(Canvas canvas){
        mPath.reset();
        mPaint.reset();
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setColor(mStepTextColor);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(getWidth()/100);
        mPaint.setTextSize(getWidth()/10);
        float y = getHeight()/2+getWidth()/10+getWidth()/5+5;
        float x = getWidth()/2;
        canvas.drawText(mStepText,x,y,mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        initData();
        outerRace(canvas);
        innerRace(canvas);
        titleText(canvas);
        currentNumText(canvas);
        stepText(canvas);
        postInvalidateDelayed(1);

    }
}
/**
 *@content:自定义柱状图View
 *@time:2018-7-31
 *@build:
 */

public class BarGraphView extends View {
    private final String TAG = "BarGraphView";
    private List<Item> mItemList = new ArrayList<>();;
    private Paint mPaint;
    private Paint mPaintTiemText;
    private Paint mPaintCurrenNumText;
    private Path mPath;
    private Path mSrc;
    private float mWPadding;//宽边距 X边距
    private float mHPadding;//高边距 Y边距
    private float mSpacing;// item之间的间距
    private float mItemWidth; //item 的宽度
    private float mItemHeight; //item 的高度
    private float mItemNum; // item 的数量
    private float mBottomLine; //底线上的Y坐标值
    private float mMaxValue;
    //颜色组
    private int[] mItemColors ;
    private float[] mItemColorsPosition;
    private int mTiemTextColor;
    private int mCurrenNumTextColor;


    public BarGraphView(Context context) {
        super(context);
        initPaint();
    }

    public BarGraphView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public BarGraphView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    /**
     * 添加数据的方法
     * @param item  例子:view.addData(new BarGraphView.Item("12-7",1651));
     */
    public void addData(Item item){
        mItemList.add(item);
        //计算添加到List中的最大值,并且给最大值增加2000上限
        mMaxValue = 0;
        if(!mItemList.isEmpty()) {
            for (int j = 0; j < mItemList.size(); j++) {
                float numA = mItemList.get(j).currenNum;
                if (mMaxValue < numA) {
                    mMaxValue = numA;
                }
            }
            mMaxValue = mMaxValue + 2000;
        }
    }

    public List<Item> getData(){
        return mItemList;

    }

    /**
     * 设置颜色的方法
     * @param mItemColors 圆柱体的颜色组
     * @param mItemColorsPosition 圆柱体的颜色组渐变点
     * @param mTiemTextColor 时间text的颜色
     * @param mCurrenNumTextColor 步数text的颜色
     */
    public void setColors(int[] mItemColors,float[] mItemColorsPosition,int mTiemTextColor,int mCurrenNumTextColor){
        this.mItemColors = mItemColors;
        this.mItemColorsPosition = mItemColorsPosition;
        this.mTiemTextColor = mTiemTextColor;
        this.mCurrenNumTextColor = mCurrenNumTextColor;
    }


    private void initPaint(){
        this.mPaint = new Paint();
        this.mPaintTiemText = new Paint();
        this.mPaintCurrenNumText = new Paint();
        this.mPath = new Path();
        this.mSrc = new Path();
    }
    private void initData(){
        if(!mItemList.isEmpty()) {
            mItemNum = mItemList.size();
        }
        if(mItemColors == null){
            mItemColors = new int[]{0xFF2BF19E,0xFF1BE2FC};
        }
        if (mItemColorsPosition == null){
            mItemColorsPosition = new float[]{0.2f,0.8f};
        }
        if (mTiemTextColor == 0){
            mTiemTextColor = Color.BLACK;
        }
        if (mCurrenNumTextColor == 0){
            mCurrenNumTextColor = Color.BLACK;
        }

        mWPadding = getWidth()/20; //宽度内边距
        mHPadding = getHeight()/10; //高度内边距
        mItemWidth = getWidth()/(10+mItemNum);  //圆柱体的宽度
        mBottomLine = getHeight()-mHPadding*2; //底部横线坐标
        if(mItemList.size() == 1){
            //只有一个item时,处理圆柱间距
            mSpacing = getWidth()/2 - mItemWidth;
        }else if (mItemList.size() == 2) {
            //只有二个item时,处理圆柱间距
            mSpacing = getWidth() / 4;
        }else if (mItemList.size() == 3){
            //只有三个item时,处理圆柱间距
            mSpacing = getWidth() / 6;
        }else {
            mSpacing = ((getWidth() - mWPadding*2 - mItemWidth*mItemNum)/mItemNum)/1.15f; //圆柱体之间的间距
        }


    }

    /**
     * 画底部横线
     * @param canvas 画布
     */
    private void drawXline(Canvas canvas){
        mPaint.reset();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(2);
        int [] colors = new int[]{0xFF7E42FF,0xFF2BB5FA};
        float[] colorsPosition = new float[]{0.2f,0.6f};
        RadialGradient rg = new RadialGradient(getWidth()/2,
                getHeight()-mHPadding*2,
                getWidth(),
                colors,colorsPosition,Shader.TileMode.CLAMP);
        mPaint.setShader(rg);
        canvas.drawLine(mWPadding,getHeight()-mHPadding*2,getWidth()-mWPadding,getHeight()-mHPadding*2,mPaint);

    }

    /**
     * 画圆柱 画日期 画数值
     * @param canvas 画布
     */
    private void drawItem(Canvas canvas){
        mPaint.reset();
        mPaintTiemText.reset();
        mPaintCurrenNumText.reset();
        mPath.reset();
        //柱状图画笔
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.BLUE);
        LinearGradient lg = new LinearGradient(0,getHeight(),getWidth(),0,mItemColors,mItemColorsPosition,Shader.TileMode.CLAMP);
        mPaint.setShader(lg);
        //日期画笔
        mPaintTiemText.setAntiAlias(true);
        mPaintTiemText.setStyle(Paint.Style.FILL);
        mPaintTiemText.setStrokeWidth(5);
        mPaintTiemText.setTextSize(getWidth()/35);
        mPaintTiemText.setTextAlign(Paint.Align.LEFT);
        mPaintTiemText.setColor(mTiemTextColor);
        //数值画笔
        mPaintCurrenNumText.setAntiAlias(true);
        mPaintCurrenNumText.setStyle(Paint.Style.FILL);
        mPaintCurrenNumText.setStrokeWidth(5);
        mPaintCurrenNumText.setTextSize(getWidth()/35);
        mPaintCurrenNumText.setTextAlign(Paint.Align.LEFT);
        mPaintCurrenNumText.setColor(mCurrenNumTextColor);
        mItemHeight = (getHeight() - mHPadding * 3) * (mItemList.get(0).currenNum / mMaxValue);
        if(!mItemList.isEmpty()) {
            //画第一个圆柱
            RectF rect = new RectF();
            rect.left = mWPadding + mSpacing;
            rect.top = mBottomLine - mItemHeight;
            rect.right = mWPadding + mSpacing + mItemWidth;
            rect.bottom = mBottomLine;
            mPath.addRect(rect, Path.Direction.CW);
            //画日期
            canvas.drawText(mItemList.get(0).time,
                    mWPadding + mSpacing,
                    mBottomLine + mHPadding,
                    mPaintTiemText);
            //画数值
            canvas.drawText(Integer.toString((int) (mItemList.get(0).currenNum)),
                    mWPadding + mSpacing,
                    mBottomLine - mItemHeight - 5,
                    mPaintCurrenNumText);
            //画剩下的圆柱
                for (int i = 1; i < mItemList.size(); i++) {
                    Item item = mItemList.get(i);
                    mItemHeight = (getHeight() - mHPadding * 3) * (item.currenNum / mMaxValue);
                    RectF rectF = new RectF();
                    rectF.left = mWPadding + mSpacing * (i + 1) + mItemWidth * i;
                    rectF.top = mBottomLine - mItemHeight;
                    rectF.right = mWPadding + mSpacing * (i + 1) + mItemWidth * (i + 1);
                    rectF.bottom = mBottomLine;
                    mSrc = new Path();//画单个圆柱
                    mSrc.addRect(rectF, Path.Direction.CW);
                    mPath.addPath(mSrc);//将单个圆柱添加到mPath中
                    canvas.drawText(item.time,
                            mWPadding + mSpacing * (i + 1) + mItemWidth * i,
                            mBottomLine + mHPadding,
                            mPaintTiemText);//画日期
                    canvas.drawText(Integer.toString((int) (item.currenNum)),
                            mWPadding + mSpacing * (i + 1) + mItemWidth * i,
                            mBottomLine - mItemHeight - 5,
                            mPaintCurrenNumText);//画步数
                }
                canvas.drawPath(mPath, mPaint);//一次性添加全部圆柱
        }else {
            mPaintTiemText.setTextSize(getWidth()/20);
            canvas.drawText("无数据",getWidth()/2,getHeight()/2,mPaintTiemText);
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        initData();
        drawXline(canvas);
        drawItem(canvas);
    }

     public static class Item {
        public String time;
        public float currenNum;
        public Item (String time,float currenNum){
            this.time = time;
            this.currenNum = currenNum;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37217804/article/details/81408763