Android仿支付宝信用分仪表盘控件

无意间打开Github,发现自己的一个自定义控件项目竟然神奇的被Star了,真的是相当惊喜,毕竟这是自己从事代码工作以来收获的第一个Star,于是才有了以下这篇博客。花点时间将代码整理了一下,也配上了一张效果图,粗糙地完成了以下这篇博客,作为一个笔记进行总结整理,同时提供了一个分享途径。好了,话不多说,先上效果图:

示例图片

以下是主要构造

public DashBoardProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        dashBoardView = new DashBoardView(context, attrs);
        addView(dashBoardView, layoutParams);
        pointView = new PointView(context, attrs);
        addView(pointView, layoutParams);
        scoreTextView = new ScoreTextView(context, attrs);
        addView(scoreTextView, layoutParams);
    }

通过以上构造方法,可以看到该控件主要由三个View组成,分别命名为:

  1. DashBoardView(外边框和信用等级显示,刷新频率最低,只在值满足条件的时候刷新)
  2. PointView(进度显示的点,一直在刷新)
  3. ScoreTextView(信用分数,一直在刷新)

由于刷新频率不同,同时根据具体绘制的内容,认为分为三个部分还是较合理的,如果放在一个View中进行onDraw()绘制,会导致大量不必要的部分重复绘制。接下来拆分为四个部分进行讲解,包含以上三个View和一个对外提供的刷新的方法。

1.PointView(容易理解的View)

说其最容易理解是因为它仅仅是一个小圆点围着表盘的中心点不断转动到预设的值,实现原理就是不断改变绘制角度后调用onDraw()方法刷新,见关键代码:

private class PointView extends View {

        public PointView(Context context) {
//            super(context);
            this(context, null);
        }

        public PointView(Context context, AttributeSet attrs) {
            super(context, attrs);
            /*
            * <p>Causes the Runnable to be added to the message queue.
            * The runnable will be run on the user interface thread.</p>
            * */
            post(new Runnable() {
                @Override
                public void run() {
                    initPaint();
                }
            });
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            //转移画布使绘制的内容在所给区域的中央
            if (306 / 576F > height / width) {  //给出的大小可能是不和我们的控件匹配的
                canvas.translate(Math.abs(width - reguSizeX) / 2, 0);
            } else {
                canvas.translate(0, Math.abs(height - reguSizeY) / 2);
            }

            //绘制圆点
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(rotation);
            canvas.drawCircle(0, -278 / 576f * reguSizeX, 6 / 306f * reguSizeY, paint);
            canvas.restore();
        }
    }

以上代码中有两个需要注意的地方:

1.由于要适配大小,所以有些操作要放在onMeasure之后,但是又必须在绘制之前,使用

post(new Runnable() {
                @Override
                public void run() {
                    initPaint();
                }
            });

方法能够解决这个问题,在绘制圆点的时候还不能很好的体现这个方法的作用,后面绘制文字的时候,由于文字大小也要做适配,所以必须先获得文字大小再进行绘制,所以将绘制文字的画笔初始化放在了post中,以设置适配了整体布局大小之后的文字大小(有点描述不清,希望能够理解……)

2.刷新点的位置的时候先将画布中心转移到半圆的中间,然后不断旋转画布,再绘制圆,达到小圆点不断移动的效果

2.ScoreTextView(最容易理解的View)

这个view的代码见最后的总代码,只有一个简单的绘制文字到画布中间,用来显示分数,唯一的难点在上面的PointView中已经做了解释,使用post在绘制之前获取布局大小以用来适配并设置要设置的文字大小,同时简单的使用了一个canvas.clipRect()方法来防止绘制脏布局(经过测试好像并没有什么效果)

3.DashBoardView(相对复杂的View)

相对复杂指的是该View相对于前面分析的两个View来说要复杂一些,其实控件本身并不复杂,只是要绘制的内容多一点,包括线性边框,分段边框,断点组成的边框和相关文字部分,其中相对复杂的就是那个由点组成的边框了,其实也是使用了旋转画布的原理,旋转画布来简化具有一定规则的图形绘制在这篇博客中有详细的例子:

http://blog.csdn.net/aigestudio/article/details/41799811

个人认为还有一个比较坑的地方就是根据原型图来测量文字所在的地方,将文字绘制到固定的位置,该部分少不了要进行位置的适配,这些细节工作才是比较花时间的部分。给View对应的具体代码在文章后面给出。

该自定义控件已经写成了一个小项目放在了github上,地址:

https://github.com/shixiuwen/DashBoardProgressView

4.刷新方法:refreshScore(int refreshToScore)

刷新方法的代码如下:

/**
     * 模拟刷新小圆点的位置
     */
    public void refreshScore(final int refreshToScore) {
        score = 500;
        rotation = -90;
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    while (score < refreshToScore) {
                        Thread.sleep(50);
                        rotation += 1;
                        score += 2.222;
                        if (score >= refreshToScore) {  //该判断非常重要,防止每次加2.22超出边界
                            score = refreshToScore;
                        }
                        pointView.postInvalidate();
                        scoreTextView.postInvalidate();
                        double tempScore = score + 0.5;
                        if (tempScore < 600) {
                            scoreLever = 0;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 600 && tempScore <= 603) {
                            scoreLever = 1;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 700 && tempScore <= 703) {
                            scoreLever = 2;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 800 && tempScore <= 803) {
                            scoreLever = 3;
                            dashBoardView.postInvalidate();
                        }
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

我们在方法中开启了一个子线程不断使用postInvalidate()方法已达到小圆点移动和分数刷新的效果,通过循环 while (score < refreshToScore) 来控制刷新的时机,当分数大于或者等于设置的分数的时候停止刷新,这其中有一个需要注意的地方,分数和角度是对应的,不是1:1的比例增加的,比如我这个地方需要用到的就是1:2.22(根据实际需求),如下:

rotation += 1;
score += 2.222;

也就是圆点每旋转一个角度,要增加两分,所以可能会出现如果设置的分数是700,每次加2.22刚好最后一次加到了702.22(只是举例,不一定是这个)才停止的情况,所以我们添加了以下代码进行约束,这也是在代码中注明特别重要的原因,不然会导致结果不准确。

rotation += 1;
score += 2.222;
if (score >= refreshToScore) {  //该判断非常重要,防止每次加2.22超出边界
      score = refreshToScore;
}

以下是所有代码:

DashBoardProgressView.java
package com.shixia.dashboardprogressview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;

/**
 * Created by AmosShi on 2016/10/27.
 * <p>
 * Description:仿支付宝信用分表盘控件,自动更新进度,已做好屏幕适配工作,见Demo
 * <p>
 * Email:shixiuwen1991@yeah.net
 * <p>
 * 分析:
 * 3个层级:
 * 1.无需更新的边框刻度以及分数文字刻度等
 * 2.随刻度移动而变化的文字部分
 * 3.移动更新的刻度点
 */

public class DashBoardProgressView extends FrameLayout {

    private Paint paint;
    private Paint textPaint38;
    private Paint textPaint20;
    private Paint textPaint60;
    private RectF rectF;
    private RectF rectF2;

    private float rotation = -90;
    private double score = 500;
    private int scoreLever = 0;

    private PointView pointView;
    private ScoreTextView scoreTextView;
    private DashBoardView dashBoardView;

    private float reguSizeX = 0;   //以此为参考缩放控件以得到合适大小
    private float reguSizeY = 0;

    private float width;
    private float height;

    public DashBoardProgressView(Context context) {
//        super(context);
        this(context, null);
    }

    public DashBoardProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        Log.i("amos", "init");
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        dashBoardView = new DashBoardView(context, attrs);
        addView(dashBoardView, layoutParams);
        pointView = new PointView(context, attrs);
        addView(pointView, layoutParams);
        scoreTextView = new ScoreTextView(context, attrs);
        addView(scoreTextView, layoutParams);
    }

    private void initPaint() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.WHITE);
        paint.setStrokeCap(Paint.Cap.ROUND);
    }

    private void initTextPaint38() {
        textPaint38 = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        textPaint38.setStyle(Paint.Style.STROKE);
        textPaint38.setColor(Color.WHITE);
        textPaint38.setStrokeCap(Paint.Cap.ROUND);
        textPaint38.setTextSize(38 / 306f * reguSizeY);
    }

    private void initTextPaint20() {
        textPaint20 = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        textPaint20.setStyle(Paint.Style.STROKE);
        textPaint20.setColor(Color.WHITE);
        textPaint20.setStrokeCap(Paint.Cap.ROUND);
        textPaint20.setTextSize(20 / 306f * reguSizeY);
    }

    private void initTextPaint60() {
        textPaint60 = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        textPaint60.setStyle(Paint.Style.STROKE);
        textPaint60.setColor(Color.WHITE);
        textPaint60.setStrokeCap(Paint.Cap.ROUND);
        textPaint60.setTextSize(60 / 306f * reguSizeY);
    }

    private void initRectF() {
        Rect rect = new Rect((int) (10 / 576f * reguSizeX), (int) (10 / 306f * reguSizeY), (int) (566 / 576f * reguSizeX), (int) (566 / 306f * reguSizeY));
        rectF = new RectF(rect);

        Rect rect2 = new Rect((int) (42 / 576f * reguSizeX), (int) (42 / 306f * reguSizeY), (int) (534 / 576f * reguSizeX), (int) (534 / 306f * reguSizeY));
        rectF2 = new RectF(rect2);
    }

    /**
     * 模拟刷新小圆点的位置
     */
    public void refreshScore(final int refreshToScore) {
        score = 500;
        rotation = -90;
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    while (score < refreshToScore) {
                        Thread.sleep(50);
                        rotation += 1;
                        score += 2.222;
                        if (score >= refreshToScore) {  //该判断非常重要,防止每次加2.22超出边界
                            score = refreshToScore;
                        }
                        pointView.postInvalidate();
                        scoreTextView.postInvalidate();
                        double tempScore = score + 0.5;
                        if (tempScore < 600) {
                            scoreLever = 0;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 600 && tempScore <= 603) {
                            scoreLever = 1;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 700 && tempScore <= 703) {
                            scoreLever = 2;
                            dashBoardView.postInvalidate();
                        } else if (tempScore >= 800 && tempScore <= 803) {
                            scoreLever = 3;
                            dashBoardView.postInvalidate();
                        }
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private class DashBoardView extends View {

        public DashBoardView(Context context) {
//            super(context);
            this(context, null);
        }

        public DashBoardView(Context context, AttributeSet attrs) {
            super(context, attrs);
            /*
            * <p>Causes the Runnable to be added to the message queue.
            * The runnable will be run on the user interface thread.</p>
            * 使用了post后,run()中的代码会提前加载到message queue,提前于onDraw()方法的
            * 执行,以初始化一些数据,有些数据数据是onMeasure()方法中返回的,不这么做的话无法
            * 计算比例以适配大小
            * */
            post(new Runnable() {
                @Override
                public void run() {
                    initPaint();
                    initTextPaint38();
                    initTextPaint20();
                    initRectF();
                }
            });

        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            //转移画布使绘制的内容在所给区域的中央
            if (306 / 576F > height / width) {  //给出的大小可能是不和我们的控件匹配的
                canvas.translate(Math.abs(width - reguSizeX) / 2, 0);
            } else {
                canvas.translate(0, Math.abs(height - reguSizeY) / 2);
            }

            //绘制文字
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.drawText("700", -15 / 576f * reguSizeX, -168 / 306f * reguSizeY, textPaint20);
            canvas.restore();

            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(45);
            canvas.drawText("800", -15 / 576f * reguSizeX, -168 / 306f * reguSizeY, textPaint20);
            canvas.restore();

            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(-45);
            canvas.drawText("600", -15 / 576f * reguSizeX, -168 / 306f * reguSizeY, textPaint20);
            canvas.restore();

            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.drawText("500", -184 / 576f * reguSizeX, 8 / 306f * reguSizeY, textPaint20);
            canvas.restore();

            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.drawText("900", 148 / 576f * reguSizeX, 8 / 306f * reguSizeY, textPaint20);
            canvas.restore();

            if (scoreLever == 0) {
                canvas.drawText("信用较差", 213 / 576f * reguSizeX, 196 / 306f * reguSizeY, textPaint38);
            } else if (scoreLever == 1) {
                canvas.drawText("信用一般", 213 / 576f * reguSizeX, 196 / 306f * reguSizeY, textPaint38);
            } else if (scoreLever == 2) {
                canvas.drawText("信用较好", 213 / 576f * reguSizeX, 196 / 306f * reguSizeY, textPaint38);
            } else if (scoreLever == 3) {
                canvas.drawText("信用极好", 213 / 576f * reguSizeX, 196 / 306f * reguSizeY, textPaint38);
            }

            //绘制最外框
            paint.setStrokeWidth(8 / 306f * reguSizeY);
            canvas.drawArc(rectF, 175, 190, false, paint);

            //绘制内边框1,2,3,4,5,6分段(带有断点的内边框)
            paint.setStrokeCap(Paint.Cap.BUTT);
            paint.setStrokeWidth(16 / 306f * reguSizeY);
            canvas.drawArc(rectF2, 175, 4, false, paint);
            canvas.drawArc(rectF2, 181, 43, false, paint);
            canvas.drawArc(rectF2, 226, 43, false, paint);
            canvas.drawArc(rectF2, 271, 43, false, paint);
            canvas.drawArc(rectF2, 316, 43, false, paint);
            canvas.drawArc(rectF2, 1, 4, false, paint);

            //绘制大圆点
            paint.setStrokeWidth(6 / 306f * reguSizeY);
            canvas.save();
            canvas.drawLine(288 / 576f * reguSizeX, 96 / 306f * reguSizeY, 288 / 576f * reguSizeX, 76 / 306f * reguSizeY, paint);
            canvas.restore();
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(45);
            canvas.drawLine(0, -192 / 306f * reguSizeY, 0, -212 / 306f * reguSizeY, paint);
            canvas.restore();
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288);
            canvas.rotate(90);
            canvas.drawLine(0, -192 / 306f * reguSizeY, 0, -212 / 306f * reguSizeY, paint);
            canvas.restore();
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(-45);
            canvas.drawLine(0, -192 / 306f * reguSizeY, 0, -212 / 306f * reguSizeY, paint);
            canvas.restore();
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288);
            canvas.rotate(-90);
            canvas.drawLine(0, -192 / 306f * reguSizeY, 0, -212 / 306f * reguSizeY, paint);
            canvas.restore();

            //绘制小圆点
            paint.setStrokeCap(Paint.Cap.ROUND);
            for (int i = -19; i < 20; i++) {
                canvas.save();
                canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
                canvas.rotate(4.5f * i);
                canvas.drawLine(0, -192 / 306f * reguSizeY, 0, -202 / 306f * reguSizeY, paint);
                canvas.restore();
            }
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//            setMeasuredDimension(576, 306);
            width = getMeasuredSize(widthMeasureSpec, true);
            height = getMeasuredSize(heightMeasureSpec, false);
            setMeasuredDimension((int) width, (int) height);
            if (306 / 576F > height / width) {  //给出的大小可能是不和我们的控件匹配的
                reguSizeX = height * 576 / 306;
                reguSizeY = height;
            } else {
                reguSizeX = width;
                reguSizeY = width * 306 / 576;
            }
        }
    }

    private class PointView extends View {

        public PointView(Context context) {
//            super(context);
            this(context, null);
        }

        public PointView(Context context, AttributeSet attrs) {
            super(context, attrs);
            /*
            * <p>Causes the Runnable to be added to the message queue.
            * The runnable will be run on the user interface thread.</p>
            * */
            post(new Runnable() {
                @Override
                public void run() {
                    initPaint();
                }
            });
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            //转移画布使绘制的内容在所给区域的中央
            if (306 / 576F > height / width) {  //给出的大小可能是不和我们的控件匹配的
                canvas.translate(Math.abs(width - reguSizeX) / 2, 0);
            } else {
                canvas.translate(0, Math.abs(height - reguSizeY) / 2);
            }

            //绘制圆点
            canvas.save();
            canvas.translate(288 / 576f * reguSizeX, 288 / 306f * reguSizeY);
            canvas.rotate(rotation);
            canvas.drawCircle(0, -278 / 576f * reguSizeX, 6 / 306f * reguSizeY, paint);
            canvas.restore();
        }
    }

    private class ScoreTextView extends View {

        public ScoreTextView(Context context) {
//            super(context);
            this(context, null);
        }

        public ScoreTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
            /*
            * <p>Causes the Runnable to be added to the message queue.
            * The runnable will be run on the user interface thread.</p>
            * */
            post(new Runnable() {
                @Override
                public void run() {
                    initTextPaint60();
                }
            });
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            //转移画布使绘制的内容在所给区域的中央
            if (306 / 576F > height / width) {  //给出的大小可能是不和我们的控件匹配的
                canvas.translate(Math.abs(width - reguSizeX) / 2, 0);
            } else {
                canvas.translate(0, Math.abs(height - reguSizeY) / 2);
            }
            //优化,防止绘制脏布局
            canvas.clipRect(232 / 576f * reguSizeX, 280 / 306f * reguSizeY - textPaint60.getTextSize()
                    , 232 / 576f * reguSizeX + textPaint60.measureText(String.valueOf((int) (score + 0.5))), 280 / 306f * reguSizeY);

            canvas.drawText(String.valueOf((int) (score + 0.5)), 232 / 576f * reguSizeX, 280 / 306f * reguSizeY, textPaint60);
        }
    }

    private int getMeasuredSize(int length, boolean isWidth) {
        int mode = MeasureSpec.getMode(length);
        int size = MeasureSpec.getSize(length);
        int resSize = 0;
        if (mode == MeasureSpec.EXACTLY) {
            resSize = size;
        } else {
            if (mode == MeasureSpec.AT_MOST) {
                if (isWidth) {
                    resSize = 576;
                } else {
                    resSize = 306;
                }
            }
        }
        return resSize;
    }

}
MainActivity.java
package com.shixia.dashboardprogressview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import com.shixia.dashboardprogressview.view.DashBoardProgressView;

public class MainActivity extends AppCompatActivity {

    private Button btnRefreshTo550;
    private Button btnRefreshTo650;
    private DashBoardProgressView wpbView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        wpbView = (DashBoardProgressView) findViewById(R.id.wpb_progress_view);

        btnRefreshTo550 = (Button) findViewById(R.id.btn_refresh_to550);
        btnRefreshTo650 = (Button) findViewById(R.id.btn_refresh_to650);

        wpbView.refreshScore(800);

        btnRefreshTo550.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                wpbView.refreshScore(550);
            }
        });

        btnRefreshTo650.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                wpbView.refreshScore(650);
            }
        });

    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
    android:layout_width="match_parent" android:layout_height="match_parent"
    tools:context="com.shixia.dashboardprogressview.MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#dcdcdc">
        <LinearLayout
            android:layout_width="1000px"
            android:layout_height="800px"
            android:layout_centerInParent="true"
            android:background="#43c0dc"
            android:gravity="center">

            <com.shixia.dashboardprogressview.view.DashBoardProgressView
                android:layout_width="580px"
                android:layout_height="300px"
                android:layout_centerInParent="true"
                android:id="@+id/wpb_progress_view"/>

        </LinearLayout>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn_refresh_to550"
            android:text="refresh To 550"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="100px"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn_refresh_to650"
            android:text="refresh To 650"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="300px"/>

    </RelativeLayout>

</android.support.constraint.ConstraintLayout>

PS:该自定义控件除了设置刷新分数外没有对外提供相关属性设置方法,只想分享一个解决这种问题的思路,真的要使用的话请自行修改,如有任何问题请留言或者邮箱:shixiuwen1991@yeah.net

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自定义View之仿支付宝芝麻信用仪表盘效果,喜欢的话,请给个star,谢谢.使用添加项目依赖Add it in your root build.gradle at the end of repositories: allprojects {         repositories { ... maven { url "https://jitpack.io" }         }     } Add the dependency     dependencies {             compile 'com.github.HotBitmapGG:CreditSesameRingView:V1.0.2' }新版芝麻信用使用     // The gradient color can define your own private final int[] mColors = new int[]{             0xFFFF80AB,             0xFFFF4081,             0xFFFF5177,             0xFFFF7997              }; // Set up the need to score mLayout = (RelativeLayout) view.findViewById(R.id.layout);       mButton = (Button) view.findViewById(R.id.btn);       newCreditSesameView = (NewCreditSesameView) view.findViewById(R.id.sesame_view);       mLayout.setBackgroundColor(mColors[0]);       mButton.setOnClickListener(new View.OnClickListener()       { @Override public void onClick(View view)            {                newCreditSesameView.setSesameValues(639);                startColorChangeAnim();            }       }); // The background color gradient animation Simply illustrates the effect Can customize according to your need public void startColorChangeAnim()      { ObjectAnimator animator = ObjectAnimator.ofInt(mLayout, "backgroundColor", mColors);          animator.setDuration(3000);          animator.setEvaluator(new ArgbEvaluator());          animator.start();      }旧版芝麻信用使用      // Set up the need to score oldCreditSesameView = (OldCreditSesameView) view.findViewById(R.id.sesame_view);       mButton = (Button) view.findViewById(R.id.btn);       mButton.setOnClickListener(new View.OnClickListener()       { @Override public void onClick(View view)           {               oldCreditSesameView.setSesameValues(639);           }       });
Android仪表盘控件是一种常用于显示和控制数据的UI元素。它可以在移动设备的屏幕上呈现出类似于汽车仪表盘的视图,用于展示各种指标、数据和信息。Android提供了多种方式来实现仪表盘控件,开发者可以根据需求选择合适的控件来构建自定义的仪表盘。 常见的Android仪表盘控件包括进度条、圆形进度条等。进度条可用于表示某项任务的进度,用户可以通过触摸或拖动进度条来控制任务的进行。圆形进度条则更加直观地展示了进度的百比,适用于较为复杂的进度控制场景。 仪表盘控件还可以用于显示各种指标和数据,比如速度、温度、电量等。开发者可以根据具体需求绘制仪表盘的刻度、指针和标签,通过改变刻度和指针的位置来展示相应的数值。这些仪表盘控件可以帮助用户更直观地了解数据的变化,提供更好的用户交互体验。 除了上述基本功能,Android仪表盘控件还可以通过添加动画效果和自定义样式来提升用户体验。开发者可以为仪表盘控件添加缓慢的指针移动效果或渐变的色彩变化,增加仪表盘的视觉吸引力。同时,也可以根据应用的需求自定义仪表盘的外观,使其更加符合应用的整体风格。 总之,Android仪表盘控件是一种非常有用和常见的UI元素,可以用于展示和控制各种指标、数据和信息。开发者可以根据具体需求选择适合的控件,并通过添加动画和自定义样式来提升用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值