添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

关于自定义View:

好了,吐槽时间到.自定义view是Android开发知识体系中的重点,也是难点.好多小伙伴(也包括我)之前对自定义view也是似懂非懂.那种感觉老难受了.因此作为社会主义好青年,怎么能够不加钻研呢?那可不是你我的风格哦.因此,我将通过几篇博文来展示自定义view的基本流程.另外,我说一下,关于自定义view的学习呢,我们还是得动手敲代码,实践出真知!因此, 我强烈建议同志们先从最基本,最简单的自定义view画起,这样在自定义view的过程中,才能了解其原理,从而为以后画出各种各样炫酷的view,打下基础. OK,本片博文将通过自定义圆环,带你去探索自定义view的奥妙…

俗话说无规矩不成方圆,无图全是扯淡!

实现的效果图:

自定义圆环流程:

上图就是自定义圆环的指导图(非常重要).下面就根据这个神图,来向大家介绍下 如何自定义圆环?

Step 1:画里面的白色小圆
事实上,里面的白色圆圈如果不画的话,我们也可以画圆环,但是,但是,但是,重要的事情说三遍.强烈建议不要遗漏.因为在画圆时候,我们能对半径等参数有更加清晰,便于后续圆环的绘制.再说了,画个圆又咋了,无非几行代码的事.

Step 2:画矩形(正方形)
这个正方形是画圆环的最核心的步骤.如果想要画出图中绿色的圆环,这个正方形是必须的.注意看正方形是红边圆圈的外接圆.而这个所谓的红色圆圈正好处在圆环中间位置.图中一目了然,不在瞎啰嗦了.

Step 3:画圆环
其实到了这一步,我们的圆环就已经出来了.此处我们可以做的是圆环的属性的调节,比如,你可以调节圆环的颜色啥的
###关于自定义view的基本知识储备
如果你对自定义view的基本流程已经有了一个基本的认知的话,可以跳过次步骤.如果你不是很熟悉的话,推荐你先阅读下
Android自定义View的官方套路 ,里面介绍的还可以.

自定义圆环步骤:

Step 1: 继承View

对Android有一些了解的朋友都知道,android为我们提供的很多View都是继承与View的。所以我们自定义的View当然也是继承于View,当然如果你要自定义的View拥有某些android已经提供的控件的功能,你可以直接继承于已经提供的控件。

public class SuperCircleView extends View {
      public SuperCircleView(Context context) {
        this(context, null);
    public SuperCircleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        public SuperCircleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    public SuperCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
      .....
      .....

Step 2:定义自定义属性

大部分情况我们的自定义View需要有更多的灵活性,比如我们在xml中指定了颜色大小等属性,在程序运行时候控件就能展示出相应的颜色和大小。所以我们需要自定义属性自定义属性通常写在资源文件res/values/attrs.xml文件中.

贴出attr_super_circle.xml属性文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SuperCircleView">
        <!-- 圆的半径 -->
        <attr name="min_circle_radio" format="integer"/>
        <!-- 圆环的宽度 -->
        <attr name="ring_width" format="float"/>
        <!-- 内圆的颜色 -->
        <attr name="circle_color" format="color"/>
        <!-- 外圆的颜色 -->
        <attr name="max_circle_color" format="color"/>
        <!-- 圆环的默认颜色 -->
        <attr name="ring_normal_color" format="color"/>
        <!-- 圆环要显示的彩色的区域(随着数值的改变,显示不同大小的彩色区域)-->
        <attr name="ring_color_select" format="integer"/>
        <!-- 绘制内容的数值 -->
        <attr name="maxValue" format="integer" />
        <attr name="value" format="integer" />
    </declare-styleable>
</resources>

Step 3:在xml中引用自定义的圆环控件

其实这一步,正常情况下是应该放在自定义圆环完成之后.但是为了演示Step4中获取自定义属性的逻辑,暂时放在这一步了.由于通常我们需要拿到属性做一些事情,因此就需要在xml中设置了控件自定义属性。否则定义自定义属性就没有意义了。
直接上布局文件activity_main.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=".MainActivity">
    <FrameLayout
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center">
        <com.example.zq.drawcircledemo.SuperCircleView
            android:id="@+id/superview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            app:maxValue="100"
            app:value="20"
            app:ring_width="60" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="60dp"
            android:text="信息完成度"
            android:textColor="#CFD5DE"
            android:textSize="18sp" />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0"
                android:textColor="#506946"
                android:textSize="80sp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="%"
                android:textSize="28sp" />
        </LinearLayout>
    </FrameLayout>
</LinearLayout>

布局文件中的

   app:maxValue="100"
   app:ring_width="60" 

设置的属性就是我们在attr.xml中定义的.至于如何获取这些自定义属性的数值,后面会展示.

Step 4:自定义圆环初始化操作

有三个构造方法(一个参数、两个参数、三个参数),其中两个参数的构造方法必须有。

在 public SuperCircleView(Context context, AttributeSet attrs, int defStyleAttr){…}中进行初始化的操作.基本是一些获取自定义属性的操作

public class SuperCircleView extends View {
    private final String TAG = "SuperCircleView";
    private ValueAnimator valueAnimator;
    private int mViewCenterX;   //view宽的中心点(可以暂时理解为圆心)
    private int mViewCenterY;   //view高的中心点(可以暂时理解为圆心)
    private int mMinRadio; //最里面白色圆的半径
    private float mRingWidth; //圆环的宽度
    private int mMinCircleColor;    //最里面圆的颜色
    private int mRingNormalColor;    //默认圆环的颜色
    private Paint mPaint;
    private int color[] = new int[3];   //渐变颜色
    private RectF mRectF; //圆环的矩形区域
    private int mSelectRing = 0; //要显示的彩色区域(岁数值变化)
    private int mMaxValue;
    public SuperCircleView(Context context) {
        this(context, null);
    public SuperCircleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    public SuperCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuperCircleView);
        //最里面白色圆的半径
        mMinRadio = a.getInteger(R.styleable.SuperCircleView_min_circle_radio, 300);
        //圆环宽度
        mRingWidth = a.getFloat(R.styleable.SuperCircleView_ring_width, 40);
        //最里面的圆的颜色(绿色)
        mMinCircleColor = a.getColor(R.styleable.SuperCircleView_circle_color, context.getResources().getColor(R.color.green));
        //圆环的默认颜色(圆环占据的是里面的圆的空间)
        mRingNormalColor = a.getColor(R.styleable.SuperCircleView_ring_normal_color, context.getResources().getColor(R.color.gray));
        //圆环要显示的彩色的区域
        mSelectRing = a.getInt(R.styleable.SuperCircleView_ring_color_select, 0);
        mMaxValue = a.getInt(R.styleable.SuperCircleView_maxValue, 100);
        a.recycle();
        //抗锯齿画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //防止边缘锯齿
        mPaint.setAntiAlias(true);
        //需要重写onDraw就得调用此
        this.setWillNotDraw(false);
        //圆环渐变的颜色
        color[0] = Color.parseColor("#FFD300");
        color[1] = Color.parseColor("#FF0084");
        color[2] = Color.parseColor("#16FF00");

Step 5:画圆环

首先说一些,自定义view的话一般会重写一下三个方法:
onDraw(): 是用来绘制View图像,这个方法必须有.
onMeasure(): 用于改变View 的大小。
onLayout(): 用于改变View在父控件中的位置

Ok,继续.
(1).确定待画里面圆形以及矩形的位置

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //view的宽和高,相对于父布局(用于确定圆心)
        int viewWidth = getMeasuredWidth();
        int viewHeight = getMeasuredHeight();
        mViewCenterX = viewWidth / 2;
        mViewCenterY = viewHeight / 2;
        //画矩形
        mRectF = new RectF(mViewCenterX - mMinRadio - mRingWidth / 2, mViewCenterY - mMinRadio - mRingWidth / 2, mViewCenterX + mMinRadio + mRingWidth / 2, mViewCenterY + mMinRadio + mRingWidth / 2);

(2).绘制圆环

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(mMinCircleColor); canvas.drawCircle(mViewCenterX, mViewCenterY, mMinRadio, mPaint); //画默认圆环 drawNormalRing(canvas); //画彩色圆环 drawColorRing(canvas); * 画默认圆环 * @param canvas private void drawNormalRing(Canvas canvas) { Paint ringNormalPaint = new Paint(mPaint); ringNormalPaint.setStyle(Paint.Style.STROKE); ringNormalPaint.setStrokeWidth(mRingWidth); ringNormalPaint.setColor(mRingNormalColor);//圆环默认颜色为灰色 canvas.drawArc(mRectF, 360, 360, false, ringNormalPaint); * 画彩色圆环 * @param canvas private void drawColorRing(Canvas canvas) { Paint ringColorPaint = new Paint(mPaint); ringColorPaint.setStyle(Paint.Style.STROKE); ringColorPaint.setStrokeWidth(mRingWidth); ringColorPaint.setShader(new SweepGradient(mViewCenterX, mViewCenterX, color, null)); //逆时针旋转90度 canvas.rotate(-90, mViewCenterX, mViewCenterY); canvas.drawArc(mRectF, 360, mSelectRing, false, ringColorPaint); ringColorPaint.setShader(null);

ok,代码中的注释已经很详细了,我就不再细说了.

我只想说一下,代码中在绘制彩色圆环的时canvas.rotate(-90, mViewCenterX, mViewCenterY);注释中已经说了左边旋转90度.那么问题来了为什么要逆时针旋转90度呢?
这个是因为在后面画渐变色的圆弧时,drawArc和SweepGradient这两个类的起始点0度不是在我们习惯的圆环最上面那个点,而是从圆环最右边那个点开始,所以逆时针旋转90度就能让它从最上面的点开始.

盗图演示:
这里写图片描述

这下明白了吧.如果你还体会不深刻的话,就让你看一下,假如不逆时针旋转90度的话,是什么样的效果吧.
这里写图片描述

看到需要逆时针旋转90度的区别了吧.

Step 6:设置自定义view的部分监听事件

通过上述步骤我们所需的圆环基本完成了.但是,要知道,画圆环不是目的,目的是让圆环去传表达或者描述一些信息,常用的场景,比如用来显示计步器的步数,显示文件下载的完成度等等.因此我们可以适当的添加点监听事件.

 //***************************************用于更新圆环表示的数值*****************************************************
 /**
     * 设置当前值
     * @param value
    public void setValue(int value,TextView textView) {
        if (value > mMaxValue) {
            value = mMaxValue;
        int start = 0;
        int end = value;
        startAnimator(start, end, 2000,textView);
    private void startAnimator(int start, int end, long animTime, final TextView textView) {
        valueAnimator = ValueAnimator.ofInt(start, end);
        valueAnimator.setDuration(animTime);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.i(TAG, "onAnimationUpdate: animation.getAnimatedValue()::"+animation.getAnimatedValue());
                int i = Integer.valueOf(String.valueOf(animation.getAnimatedValue()));
                textView.setText(i + "");
                //每个单位长度占多少度
                 mSelectRing=(int) (360 * (i / 100f));
                Log.i(TAG, "onAnimationUpdate: mSelectRing::"+mSelectRing);
                invalidate();
        });
        valueAnimator.start();

主程序 MainActivity.java:

  public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    SuperCircleView mSuperCircleView;
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.tv);
        mSuperCircleView = findViewById(R.id.superview);
        mSuperCircleView.setValue(100, textView);
        mSuperCircleView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //随机设定圆环大小
                int i = new Random().nextInt(100) + 1;
                Log.i(TAG, "onClick: i::" + i);
                mSuperCircleView.setValue(i, textView);
        });

上述代码中设计属性动画ValueAnimator的相关知识,有兴趣的同学自己学习下.
好了,至此,自定义圆环结束.如果有疑问的话,请留言.诺诺的说一句,如果你感觉这篇文章写的还行的话,请给个赞.我感觉我需要被鼓励,哈哈,开玩笑的…

附上示例:
https://download.csdn.net/download/zhangqunshuai/10486568

 
参考文章:
一步步做Android自定义圆环百分比控件
Android自定义View的官方套路
Android 自定义view实现圆环

//绘制路径: 绘制一个圆环 private void doDrawPath(){ Bitmap.Config mConfig=mConfig = Bitmap.Config.ARGB_8888; Bitmap bm = Bitmap.createBitmap(400,400,mConfig); Canvas canvas = new Canvas(bm) Canvas类中自带圆弧函数: public void drawArc (RectF oval,float startAngle, float sweepAngle, boolean useCenter, Paint paint) 重点说明下关于角度的两个参数: startAngle:圆弧是按顺时针的,角度0与几何中0度的位置相同,即三点钟位置。但几何学中的逆时针方向角度从0到360 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar 一、实现效果图二、核心代码1.自定义MyProgressView.javapackage com.czhappy.effectdemo.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Bit... &amp;amp;amp;amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;amp;amp;amp;nbsp;如果你想读懂或者更好的理解本篇文章关于自定义圆环或圆弧的内容.请你务必提前阅读下Android自定义View之画圆环(手把手你如何一步步圆环).在这篇文章中,详细描述了最基本的自定义圆环的绘 <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 底层圆;宽高属性在 api 23以上有效;一旦生效,若与目标view的宽高不一致,那看到的效果就不正常; 可以去掉 宽高配置,在目标view上配置上 相同的 宽高就行 --> android:wid <?xml version="1.0" encoding="utf-8"?><?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/