Android——Canvas切割出扇形表盤式進度


 

Android——Canvas切割出扇形表盤式進度

一、知識點

(1)Matrix數學原理

(2)shader渲染

(3)PathEffect之DashPathEffect

 

原創者:It一zhai男

博客地址:http://www.cnblogs.com/ityizhainan/p/6306748.html

 

二、效果圖

 

(1)Matrix的數學原理[1]

在Android中,如果你用Matrix進行過圖像處理,那么一定知道Matrix這個類。Android中的Matrix是一個3 x 3的矩陣,其內容如下:

 

 

Matrix的對圖像的處理可分為四類基本變換:

Translate           平移變換

Rotate                旋轉變換

Scale                  縮放變換

Skew                  錯切變換

本例用到的是旋轉變換。

 

(2)shader渲染[2]

在Android中,提供了Shader類專門用來渲染圖像以及一些幾何圖形。

 

Shader類包括了5個直接子類,分別為:BitmapShader、ComposeShader、LinearGradient、RadialGradient以及SweepGradient。其中,BitmapShader用於圖像渲染;ComposeShader用於混合渲染;LinearGradient用於線性渲染;RadialGradient用於環形渲染;而SweepGradient則用於梯度渲染。

 

使用Shader類進行圖像渲染時,首先需要構建Shader對象,然后通過Paint的setShader()方法來設置渲染對象,最后將這個Paint對象繪制到屏幕上即可。

 

有一點需要注意,使用不同的方式渲染圖像時需要構建不同的對象。

 

SweepGradient掃描渲染

public SweepGradient(float cx,float cy,int[] colors,float[] position) 

parameters:

      float cx:渲染中心x坐標

      float cy:渲染中心y坐標

      int[] colors:圍繞中心渲染的顏色數組,顏色數組里至少要有兩種顏色

      float[] position:在顏色數組里每種顏色的相對位置,取值范圍0到1.0

 

(3)PathEffect之DashPathEffect[3]

DashPathEffect主要用於畫虛線。構造函數,看注釋,intervals必須大於大於2,phase是偏移量

 

DashPathEffect(new float[]{2,4,6,8},1)

的第一個數組參數依次是畫個長度為2的實線,再畫個長度為4的空白再畫個長度為6的實線,再畫個長度為8的虛線,寬度是由mPaint.setStrokeWidth(mHeight/10)設置。

第二個參數指定了繪制的虛線相對了起始地址(Path起點)的取余偏移(對路徑總長度)。

new DashPathEffect(new float[] { 8, 10, 8, 10}, 0);
這時偏移為0,先繪制實線,再繪制透明。


new DashPathEffect(new float[] { 8, 10, 8, 10}, 8);
這時偏移為8,先繪制了透明,再繪制了實線.(實線被偏移過去了)

可是通過不斷地遞增/遞減來改變phase的值,達到一個路徑自身不斷循環移動的動畫效果。

 

三、主要代碼

package com.example.yds.circleprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

/**
 * Created by yds on 2017/1/16.
 */

//@SuppressLint("DrawAllocation")
public class SampleView extends View {
    private Paint mPaint;
    private float mRotate;
    private Matrix mMatrix;
    private Shader mShader;
    private int mWidth;
    private int mHeight;

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

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

    public SampleView(Context context) {

        super(context);


    }
    public void getArc(Canvas canvas, float o_x, float o_y, float r,
                       float startangel, float endangel, Paint paint){
        RectF rect = new RectF(o_x - r, o_y - r, o_x + r, o_y + r);
        Path path = new Path();
        //將畫筆移動到指定點,與lineTo結合畫線。可以理解成畫線的起始點
        path.moveTo(o_x,o_y);
        //最關鍵的是下面兩句,划線終點,改點是畫布切割線與圖形的交點處
        path.lineTo((float)(o_x+r*Math.cos(startangel*Math.PI/180))
                , (float)(o_y+r*Math.sin(startangel*Math.PI/180)));
        path.lineTo((float)(o_x+r*Math.cos(endangel*Math.PI/180))
                , (float)(o_y+r*Math.sin(endangel*Math.PI/180)));
        //將要繪制的圖形添加小path中
        path.addArc(rect, startangel, endangel-startangel);
        //將path切割出來,這里切割的是畫布,並不是圖形本身
        canvas.clipPath(path);
        //畫圓
        canvas.drawCircle(o_x, o_y, r, paint);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        /**
         * Set whether this view can receive the focus.
         *設置這個視圖是否能夠得到焦點
         * Setting this to false will also ensure that this view is not focusable
         * in touch mode.
         *設置為false即使在觸摸模式下也不能得到焦點
         * @param focusable If true, this view can receive the focus.
         *設置為true,這個視圖可以獲得焦點
         * @see #setFocusableInTouchMode(boolean)
         * @attr ref android.R.styleable#View_focusable
         * */
        setFocusable(true);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMatrix = new Matrix();
        //設置獲取焦點是否在觸摸模式下
        setFocusableInTouchMode(true);
//        float x = 320;
//        float y = 200;
        /**
         * A subclass of Shader that draws a sweep gradient around a center point.
         *圍繞一個中心點渲染繪制的Shader父類
         * @param cx       The x-coordinate of the center 中心點x坐標
         * @param cy       The y-coordinate of the center 中心點y坐標
         * @param colors   The colors to be distributed between around the center.
         *                 There must be at least 2 colors in the array.
         *                 顏色分布在中心點周圍,在這個數組中必須至少有2種顏色
         * @param positions May be NULL. The relative position of
         *                 each corresponding color in the colors array, beginning
         *                 with 0 and ending with 1.0. If the values are not
         *                 monotonic, the drawing may produce unexpected results.
         *                 If positions is NULL, then the colors are automatically
         *                 spaced evenly.
         *                  可能為空。在顏色數組里的每種顏色的相對位置,取值范圍為0到1.0。
         *                  如果值不變,繪畫可能產生意想不到的結果。如果為空,那么顏色會自動均勻分布。
         */
        mShader = new SweepGradient(mWidth/2-1, mHeight/2-1, new int[] {0xFF09F68C,
                0xFFB0F44B,
                0xFFE8DD30,
                0xFFF1CA2E,
                0xFFFF902F,
                0xFFFF6433}, null);
        mPaint.setShader(mShader);
        mPaint.setStyle(Paint.Style.STROKE);
        /**DashPathEffect(new float[]{2,4,6,8},1)的第一個數組參數依次是畫個長度為2的實線,再畫個長度為4的空白
         * 再畫個長度為6的實線,再畫個長度為8的虛線,寬度是由mPaint.setStrokeWidth(mHeight/10)設置的
         *第二個參數指定了繪制的虛線相對了起始地址(Path起點)的取余偏移(對路徑總長度)。
         *
         *new DashPathEffect(new float[] { 8, 10, 8, 10}, 0);
         *這時偏移為0,先繪制實線,再繪制透明。
         *
         *new DashPathEffect(new float[] { 8, 10, 8, 10}, 8);
         *這時偏移為8,先繪制了透明,再繪制了實線.(實線被偏移過去了)
         *
         *可是通過不斷地遞增/遞減來改變phase的值,達到一個路徑自身不斷循環移動的動畫效果。
         */
        PathEffect effect = new DashPathEffect(new float[] { 10, 10, 10,10}, 0);
        //給畫筆設置繪制路徑時的特效
        mPaint.setPathEffect(effect);
        //設置線條寬度
        mPaint.setStrokeWidth(mHeight/10);



        Paint paint = mPaint;
////        float x = 320;
////        float y = 200;
//
        canvas.drawColor(Color.WHITE);
        //setRotate(mRotate,mx,my)旋轉,mRotate旋轉角度,mx,my為旋轉中心坐標。
        mMatrix.setRotate(mRotate,mWidth/2-1, mHeight/2-1);
        mShader.setLocalMatrix(mMatrix);

        mRotate += 3;
        if (mRotate >= 405) {
            mRotate = 135;
        }
        invalidate();
//        RectF rect = new RectF( mWidth/20, mWidth/20,mWidth-mWidth/20,mHeight-mWidth/20);
//        canvas.drawArc(rect,135,270,false,paint);
        getArc(canvas,mWidth/2-1, mHeight/2-1,mHeight/2-1,135,405,paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthSpecMode==MeasureSpec.EXACTLY||heightSpecMode == MeasureSpec.EXACTLY){
            mWidth = widthSpecSize;//這里的值為實際的值的3倍
            mHeight =heightSpecSize;

        }else{
            float defaultSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,200,getContext().getResources().getDisplayMetrics());
            mHeight = (int) defaultSize;
            mWidth = (int) defaultSize;
        }
        if(mWidth<mHeight){
            mHeight = mWidth;
        }else{
            mWidth = mHeight;
        }
//        Log.e("mHeight,mWidth",mHeight+","+mWidth);
        setMeasuredDimension(mWidth,mHeight);
    }
}

 

 

代碼下載:

http://download.csdn.net/detail/u013293125/9741449

 

 參考內容:

[1] http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code

[2] http://www.cnblogs.com/menlsh/archive/2012/12/09/2810372.html

[3] http://blog.csdn.net/abcdef314159/article/details/51777353


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM