Android:自定義View畫個圓再畫個弧,圓弧兩端再畫個圓

設計圖

這是設計給的設計圖,也是做出來的效果圖。不看教程的可以直接拉到最後參考代碼
在這裏插入圖片描述

嘰嘰喳喳的分析

別怪我廢話多,因爲畫這個圖老費勁了,你說平時敲代碼百度搜搜,參考參考,啥都有了。可是這圓弧兩端再加倆圓可愁死我了,啥都搜不到。第三方的那些框架長得也不像啊。於是自己進行數學分析。
開始畫:

1.繪製步驟

首先畫一個灰色的圓圈,作爲背景(灰色圓)
在這裏插入圖片描述
然後是覆蓋一段圓弧作爲進度條(藍色圓弧)
在這裏插入圖片描述
然後是最小圓的繪製,進度條開始端(薑黃圓)
在這裏插入圖片描述
然後是進度條末端圓的繪製(明黃圓)
在這裏插入圖片描述

2.分析,下圖是我分析的產物,邏輯設計圖,哈哈哈哈:

注意: 有一個需要提醒一下的是,繪製的時候,需要設置筆觸寬度,也就是setStrokeWidth這個方法。筆觸的寬度,並不是往筆觸內側增加寬度的,而是往外側增加一半,往內側增加一半。
舉例: 直線,紅色那條線纔是真正的落筆處。黃色和綠色是兩側拓寬的寬度。
如果線寬爲10,則綠色和黃色各自的寬度爲5
在這裏插入圖片描述
圓的繪製,同理
在這裏插入圖片描述
說到這裏是因爲想告訴大家,在繪製的過程中,各圓的圓心位置的確定,還需要考慮到筆觸的寬度。

爲了讓大家看明白,我專門花了幾個輔助理解的圓圈
也分別用小紅點標出了主要繪製的四個圓(灰\藍\薑黃\明黃)的圓心位置(灰原和藍弧大小一樣,圓心位置也是重合的)。
腦瓜疼的,就是那個明黃點圓心位置的確定,因爲它是動態的。

如下圖,紅色那個圓環就是我上文中提到的灰圓和藍弧所在位置。下面表述,皆用紅環來表示。紅環之間的那條黑線纔是真正落筆之處。
所以薑黃圓和明黃圓的圓心都應該在這條黑線上。
首先已知整個圖的寬度width,設筆觸的寬度爲stroke
薑黃圓根據圖示,它應該包含在紅環裏,所以它的直徑,應該爲紅環筆觸(也就是灰原和藍弧的筆觸)的寬度。
minRadius=stroke/2;
而明黃圓的直徑,我這裏想畫一個比薑黃圓的直徑大一倍的圓,所以它的直徑是薑黃圓的兩倍。
yellowRadius=stroke=2minRadius;
則紅環的半徑爲(即紅環中黑線到圓心的距離),radius=(width-4
minRadius)/2;
綜上,第一個圓的圓心座標爲(半徑+2minRadius,半徑+2minRadius),最小圓圓心爲(半徑+2minRadius,2minRadius)
最重要的明黃圓的圓心,利用三角函數
x=(radius + 2 * minRadius + radius * Math.sin(360 * progress / max * Math.PI / 180))
y=(radius + 2 * minRadius - radius * Math.cos(360 * progress / max * Math.PI / 180))

這樣就可以了。。感覺自己廢話連篇
爲了![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20190524131208154.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoYW5naHV6aWNoYW5nY2hhbmc=,size_16,color_FFFFFF,t_70
三角函數的求圓心示意圖
a和c的夾角α我們知道,斜邊c也知道,根據sinα=b/c;cosα=a/c。a和b就可以用已知條件求出來了。
over.
在這裏插入圖片描述

常識

Paint.Style.STROKE 只繪製圖形輪廓(描邊)
Paint.Style.FILL 只繪製圖形內容
Paint.Style.FILL_AND_STROKE 既繪製輪廓也繪製內容

不看教程的可以直接拉到最後參考代碼

代碼寫得是不是很蠢啊,求大佬給意見>~<
最後要插入代碼:
mark一個畫弧鏈接
未完待續–》有空的時候,記得加自定義屬性,把筆觸什麼的設置爲變量

package com.snap.awesomeserial.ui.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

public class CircleProgressView extends View {
    int progress = 0;
    private String text = "0%";
    private int max = 100;

    public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CircleProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CircleProgressView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Style.STROKE);
        int stroke=10;//筆觸,是最小圓半徑的兩倍
        int minRadius=stroke/2;
        float width = getMeasuredWidth();
        float radius = (width - minRadius*4) / 2;//最大圓的半徑
        paint.setStrokeWidth(stroke);
        paint.setColor(0xFFDBDBDB);//灰色
        canvas.drawCircle(radius + 2*minRadius, radius + 2*minRadius, radius, paint);
        paint.setStrokeWidth(stroke);
        RectF oval = new RectF(2*minRadius, 2*minRadius, radius * 2 + 2*minRadius, radius * 2 + 2*minRadius);
        paint.setColor(0xFF4080F4);//藍色
        //這是畫藍弧,第三個參數false是指,不連接到圓心
        canvas.drawArc(oval, -90, 360 * progress / max, false, paint);
        paint.setStrokeWidth(stroke);
        paint.setStyle(Style.FILL);//設置畫筆類型爲填充
        paint.setColor(0xFFD3623E);//薑黃
        RectF point = new RectF(radius + minRadius,minRadius, radius + 3*minRadius, 3*minRadius);
        //畫一個跨度360的弧,那肯定是個圓了,然後第三個參數爲true,表示連接到圓心,這就變成了一個實心圓。你也可以直接drawCircle
        canvas.drawArc(point, 0, 360, true, paint);//畫一個點
        paint.setStrokeWidth(2*stroke);
        paint.setColor(0xFFEDBC40);//明黃
        canvas.drawCircle((float) (radius + 2*minRadius + radius * Math.sin(360 * progress / max * Math.PI / 180)), (float) (radius + 2*minRadius - radius * Math.cos(360 * progress / max * Math.PI / 180)), stroke, paint);
        paint.setStyle(Paint.Style.STROKE);
        paint.setTextSize(14);
        paint.setStrokeWidth(1.0f);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        paint.setColor(Color.GRAY);
        paint.setStyle(Style.FILL);
        canvas.drawText(text, width / 2 - bounds.width() / 2,
                width / 2 + bounds.height() / 2, paint);
    }

    /**
     * 初始設置當前進度的最大值-默認100
     *
     * @param max
     */
    public void setMax(int max) {
        this.max = max;
    }

    /**
     * 更新進度和文字
     *
     * @param progress
     * @param text
     */
    public void setProgressAndText(int progress, String text) {
        this.progress = progress;
        this.text = text;
        postInvalidate();
    }

}

教程就是把其他人當傻子,所以即使調用簡單,我也要寫一遍。
隨便哪個xml文件

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:background="#000000">
    <!--這裏是調用-->
    <com.snap.awesomeserial.ui.widget.CircleProgressView
        android:id="@+id/circleView"
        android:layout_width="500dp"
        android:layout_height="500dp" />
  </LinearLayout>

然後xml對應的activity裏

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        circleView = (CircleProgressView) findViewById(R.id.circleView);
        circleView.setMax(100);
        int progress=75;
        String text ="當前溫度"+progress+"C";
        circleView.setProgressAndText(progress, text);
    }

好啦成品圖
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章