1. 程式人生 > >Android繪圖系列(二)——自定義View繪製基本圖形

Android繪圖系列(二)——自定義View繪製基本圖形

這個系列主要是介紹下Android自定義View和Android繪圖機制,自己能力有限,如果在介紹過程中有什麼錯誤,歡迎指正

前言

在上一篇Android繪圖系列(一)——自定義View基礎中我們瞭解自定義View相關的基本知識,不過,這些東西依舊還是理論,接下來我們就實際繪製一些東西

在本篇文章中,我們先了解以下Canvas,並且畫一些基本的圖形

Canvas簡介

Canvas我們可以稱之為畫布,能夠在上面繪製各種東西,是安卓平臺2D圖形繪製的基礎,非常強大。

一般來說,比較基礎的東西有兩大特點:

1.可操作性強:由於這些是構成上層的基礎,所以可操作性必然十分強大。

2.比較難用:各種方法太過基礎,想要完美的將這些操作組合起來有一定難度。**

Canvas的常用操作

操作型別 相關API 備註
繪製顏色 drawColor, drawRGB, drawARGB 使用單一顏色填充整個畫布
繪製基本形狀 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次為 點、線、矩形、圓角矩形、橢圓、圓、圓弧
繪製圖片 drawBitmap, drawPicture 繪製點陣圖和圖片
繪製文字 drawText, drawPosText, drawTextOnPath 依次為 繪製文字、繪製文字時指定每個文字位置、根據路徑繪製文字
繪製路徑 drawPath 繪製路徑,繪製貝塞爾曲線時也需要用到該函式
頂點操作 drawVertices, drawBitmapMesh 通過對頂點操作可以使影象形變,drawVertices直接對畫布作用、 drawBitmapMesh只對繪製的Bitmap作用
畫布剪裁 clipPath, clipRect 設定畫布的顯示區域
畫布快照 save, restore, saveLayerXxx, restoreToCount, getSaveCount 依次為 儲存當前狀態、 回滾到上一次儲存的狀態、 儲存圖層狀態、 回滾到指定狀態、 獲取儲存次數
畫布變換 translate, scale, rotate, skew 依次為 位移、縮放、 旋轉、錯切
Matrix(矩陣) getMatrix, setMatrix, concat 實際畫布的位移,縮放等操作的都是影象矩陣Matrix,只不過Matrix比較難以理解和使用,故封裝了一些常用的方法。

PS: Canvas常用方法在上面表格中已經全部列出了,當然還存在一些其他的方法未列出,具體可以參考官方文件 Canvas

繪製基本圖形

繪製顏色:

繪製顏色是填充整個畫布,常用於繪製底色。

canvas.drawColor(Color.RED);

首先我們寫一個類繼承View,並且我們onDraw()方法中呼叫這個方法

package com.study.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by HFS on 2017/2/4.
 */

public class CustomView extends View {
    public CustomView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.RED);
    }
}

OK,看下效果
這裡寫圖片描述

注意:接下來繪製的圖形都需要另外一個引數:Paint 可以把Canvas理解為畫布,Paint理解為畫筆

  • 初始化畫筆
  // 1.建立一個畫筆
  private Paint mPaint = new Paint();

  // 2.初始化畫筆
    private void initPaint() {
        mPaint.setColor(Color.BLACK);       //設定畫筆顏色
        mPaint.setStyle(Paint.Style.FILL);  //設定畫筆模式為填充
        mPaint.setStrokeWidth(10f);         //設定畫筆寬度為10px
    }

  // 3.在建構函式中初始化
    public xxxView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

在建立完畫筆之後,就可以在Canvas中繪製各種內容了。

繪製點

直接上程式碼了

package com.study.customview.widget;

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

/**
 * Created by HFS on 2017/2/4.
 */

public class PointView extends View {

    private Paint mPaint=new Paint();

    public PointView(Context context) {
        super(context);

        initPaint();
    }

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

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

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(10f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫一個點
        canvas.drawPoint(200,300,mPaint);

        //畫一組點
        canvas.drawPoints(new float[]{
                500,600,
                500,700,
                500,800,
                500,900

        },mPaint);
   }
}

效果圖:
這裡寫圖片描述

注意:座標點都是相對於螢幕左上角而言的。座標原點預設在左上角,水平向右為x軸增大方向,豎直向下為y軸增大方向。

繪製直線

直接上程式碼:

package com.study.customview.widget;

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

/**
 * Created by HFS on 2017/2/4.
 * 直線View
 */

public class LineView extends View {
    private Paint mPaint=new Paint();

    public LineView(Context context) {
        super(context);

        initPaint();
    }

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

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

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(10f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //從(200,300)這個點開始 到(500,600)這個點結束
        canvas.drawLine(200,400,500,600,mPaint);
        // 繪製一組線 每四數字(兩個點的座標)確定一條線
        canvas.drawLines(new float[]{
                100,200,200,200,
                100,300,200,300
        },mPaint);
    }
}

效果圖:

這裡寫圖片描述

繪製矩形

關於繪製矩形,Canvas提供了三種過載方法
這裡寫圖片描述
解釋下:
第一種就是提供四個數值(矩形左上角和右下角兩個點的座標)來確定一個矩形進行繪製。
其餘兩種是先將矩形封裝為Rect或RectF(實際上仍然是用兩個座標點來確定的矩形),然後傳遞給Canvas繪製

package com.study.customview.widget;

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.view.View;

/**
 * Created by HFS on 2017/2/4.
 */

public class RectView extends View {
    private Paint mPaint=new Paint();

    public RectView(Context context) {
        super(context);

        initPaint();
    }

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

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

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(10f);
    }

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

        //第一種
        canvas.drawRect(200,300,500,600,mPaint);
        //第二種
        Rect rect=new Rect(200,300,500,600);
        canvas.drawRect(rect,mPaint);
        //第三種
        RectF rectF=new RectF(200,300,500,600);
        canvas.drawRect(rectF,mPaint);
    }
}

效果圖
這裡寫圖片描述

為什麼會有Rect和RectF兩種?兩者有什麼區別嗎?

答案當然是存在區別的,兩者最大的區別就是精度不同,Rect是int(整形)的,而RectF是float(單精度浮點型)的。除了精度不同,兩種提供的方法也稍微存在差別,在這裡我們暫時無需關注,想了解更多參見官方文件 RectRectF

繪製圓角矩形:

同樣有兩個過載方法
這裡寫圖片描述

一般我們使用第一個

package com.study.customview.widget;

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.view.View;

/**
 * Created by HFS on 2017/2/4.
 * 圓角矩形View
 */

public class RoundRectView extends View {
    private Paint mPaint=new Paint();

    public RoundRectView(Context context) {
        super(context);

        initPaint();
    }

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

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

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(10f);
    }

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

        RectF rect=new RectF(100,100,800,400);
        canvas.drawRoundRect(rect,30,30,mPaint);
    }
}

效果圖
這裡寫圖片描述

下面簡單解析一下圓角矩形的幾個必要的引數的意思。

很明顯可以看出,第二種方法前四個引數和第一種方法的RectF作用是一樣的,都是為了確定一個矩形,最後一個引數Paint是畫筆,無需多說,與矩形相比,圓角矩形多出來了兩個引數rx 和 ry,這兩個引數是幹什麼的呢?

稍微分析一下,既然是圓角矩形,他的角肯定是圓弧(圓形的一部分),我們一般用什麼確定一個圓形呢?

答案是圓心 和 半徑,其中圓心用於確定位置,而半徑用於確定大小

由於矩形位置已經確定,所以其邊角位置也是確定的,那麼確定位置的引數就可以省略,只需要用半徑就能描述一個圓弧了。

但是,半徑只需要一個引數,但這裡怎麼會有兩個呢?

好吧,讓你發現了,這裡圓角矩形的角實際上不是一個正圓的圓弧,而是橢圓的圓弧,這裡的兩個引數實際上是橢圓的兩個半徑,他們看起來個如下圖:

紅線標註的 rx 與 ry 就是兩個半徑,也就是相比繪製矩形多出來的那兩個引數。

我們瞭解到原理後,就可以為所欲為了,通過計算可知我們上次繪製的矩形寬度為700,高度為300,當你讓 rx大於350(寬度的一半), ry大於150(高度的一半) 時奇蹟就出現了, 你會發現圓角矩形變成了一個橢圓, 他們畫出來是這樣的 ( 為了方便確認我更改了畫筆顏色, 同時繪製出了矩形和圓角矩形 ):

        // 矩形
        RectF rectF = new RectF(100,100,800,400);  

        // 繪製背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);

        // 繪製圓角矩形
        mPaint.setColor(Color.BLUE);
        canvas.drawRoundRect(rectF,700,400,mPaint);

其中灰色部分是我們所選定的矩形,而裡面的圓角矩形則變成了一個橢圓,實際上在rx為寬度的一半,ry為高度的一半時,剛好是一個橢圓,通過上面我們分析的原理推算一下就能得到,而當rx大於寬度的一半,ry大於高度的一半時,實際上是無法計算出圓弧的,所以drawRoundRect對大於該數值的引數進行了限制(修正),凡是大於一半的引數均按照一半來處理。

繪製橢圓:


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //第一種
        RectF rectF=new RectF(100,100,800,400);
        canvas.drawOval(rectF,mPaint);

        //第二種
        canvas.drawOval(100,100,800,400,mPaint);
    }
}

同樣,以上兩種方法效果完全一樣,但一般使用第一種。
這裡寫圖片描述

繪製橢圓實際上就是繪製一個矩形的內切圖形,原理如下,就不多說了:
這裡寫圖片描述

PS: 如果你傳遞進來的是一個長寬相等的矩形(即正方形),那麼繪製出來的實際上就是一個圓。

繪製圓:

繪製圓形也比較簡單, 如下:


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //在(600,600)這個點繪製一個半徑為300的圓
        canvas.drawCircle(600,600,300,mPaint);
    }

繪製圓形有四個引數,前兩個是圓心座標,第三個是半徑,最後一個是畫筆。
這裡寫圖片描述

繪製圓弧:

繪製圓弧就比較神奇一點了,為了理解這個比較神奇的東西,我們先看一下它需要的幾個引數:

// 第一種
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}

// 第二種
public void drawArc(float left, float top, float right, float bottom, float startAngle,
            float sweepAngle, boolean useCenter, @NonNull Paint paint) {}

從上面可以看出,相比於繪製橢圓,繪製圓弧還多了三個引數:

startAngle  // 開始角度
sweepAngle  // 掃過角度
useCenter   // 是否使用中心

通過字面意思我們基本能猜測出來前兩個引數(startAngle, sweepAngel)的作用,就是確定角度的起始位置和掃過角度, 不過第三個引數是幹嘛的?試一下就知道了,上程式碼:

        RectF rectF = new RectF(100,100,800,400);
        // 繪製背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);

        // 繪製圓弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF,0,90,false,mPaint);

        //-------------------------------------

        RectF rectF2 = new RectF(100,600,800,900);
        // 繪製背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF2,mPaint);

        // 繪製圓弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF2,0,90,true,mPaint);

上述程式碼實際上是繪製了一個起始角度為0度,掃過90度的圓弧,兩者的區別就是是否使用了中心點,結果如下:

這裡寫圖片描述

可以發現使用了中心點之後繪製出來類似於一個扇形,而不使用中心點則是圓弧起始點和結束點之間的連線加上圓弧圍成的圖形。這樣中心點這個引數的作用就很明顯了,不必多說想必大家試一下就明白了

相關推薦

Android繪圖系列()——定義View繪製基本圖形

這個系列主要是介紹下Android自定義View和Android繪圖機制,自己能力有限,如果在介紹過程中有什麼錯誤,歡迎指正 前言 在上一篇Android繪圖系列(一)——自定義View基礎中我們瞭解自定義View相關的基本知識,不過,這些東西依舊還

Android 定義View,繪製一個帶比例的環形進度條

最近專案有一個需求,要在首頁顯示三個環形餅狀圖,要求可以顯示比例大小,中間顯示文字部分,並且需要可以自定義顏色。設計圖如下: 思路: 繪製一個帶百分比的圓環,一共分了四個部分: 1.背景圓(就是底圖圓) 2.預設圓環 3.繪製的圓環(就是比例圓環) 4.中心文字 下面我們開始進行繪製,先準

HenCoder Android 開發進階: 定義 View 1-1 繪製基礎

自定義繪製概述 二話不說,我反手就是一個視訊:(視訊掛了,先直接點到優酷去看吧:優酷連結) 首先總結一下視訊中的關鍵點: 自定義繪製的方式是重寫繪製方法,其中最常用的是 onDraw() 繪製的關鍵是 Canvas 的使用 Canvas 的繪製類方法: drawXX

Android應用定義View繪製方法手冊

背景 這篇遲遲難產的文章算是對2015前半年的一個交代吧,那時候有一哥們要求來一發Android Canvas相關總結,這哥們還打賞了,實在不好意思,可是這事一放就給放忘了,最近群裡小夥伴催著說沒更新部落格,坐等更新啥的,隨先有這麼一篇Android應用開發超

Android定義view-繪製圓形進度條

詳細可參考:http://blog.csdn.net/Beyond0525/article/details/48181345最近專案上有一些需求,需要繪製圓形的進度條滿足設計上和互動上的需求: 實現思路在畫布上直接繪製View,需要了解一下幾點 1.需要畫一個圓 2.圓圈上有

android定義View繪製幾何圖形

1、首先說一下canvas類: Class Overview The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold

android記錄】定義view繪製矩形框

public class FackMask extends View { private static final String TAG = "FackMask"; private

Android從零開搞系列定義View(9)事件分發+事件攔截(滑動衝突)

我和一幫應屆生同學維護了一個公眾號:IT面試填坑小分隊。旨在幫助應屆生從學生過度到開發者,並且每週樹立學習目標,一同進步! 寫在前面 今天用了一天的時間去再一次梳理了一遍,事件分發和事件攔截。用了這麼長時間倒不是因為理解深刻,,而是順便看了3

Android實現定義相機系列(1)—定義view裁剪控制元件

目標 本系列文章主要記錄自定義相機拍照系列,專案原始碼還在編寫中,後續會傳到github,內容包括: 1、使用Android的Camera API自定義拍照模式,例如人臉拍照,OCR拍照等; 2、對拍完的照片進行裁剪; 3、自定義圖片伸縮view,使用手勢對圖

Android中使用定義View實現shape圖形繪製

概述 之前曾寫過一篇文章介紹了Android中drawable使用Shape資源,通過定義drawable中的shape資源能夠繪製簡單的圖形效果,如矩形,橢圓形,線形和圓環等。後來我在專案中正好遇到這樣一個需求,要在特定的位置上顯示一條垂直的虛線。正當我胸有

Android從零開搞系列定義View(4)基本定義ViewPager指示器+開源專案分析(上)

基本的自定義ViewPager的指示器 當然關於ViewPager指示器,如果只需要簡潔大方,那麼我們最簡單的方案就是使用TabLayout+ViewPager。 當然咱們也有很多非常不錯的開源框架可以選擇。 本次的記錄的內容就是

Android定義View繪製閃閃發光的文字

如何實現類似網頁效果中閃閃發光的文字,通過自定義View可以實現這一炫酷效果 1.自定義View public class FlickTextView extends TextView {

定義View 繪製一個簡單的時鐘

一.自定義類繼承View 二.思考啊... 算啦,直接上磚頭吧 自定義View介面: public class MyClockView extends View { private Handler handler = new Handler(){ @Overr

使用定義View繪製圓形進度條效果

首先自定義屬性 res - values - attrs(自己建立): <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyCicle">

定義view繪製一個跟隨手指觸控移動的小球

今天我們就來繪製一個能跟隨手指的觸控而移動的小球。其實很簡單,只要我們能夠運用自定義view中的 onTouchEvent方法我們就可以很輕易的做到。 第一步:我們使用自定義view繪製一個小球: private float x ; private float y ;

定義view繪製動態鐘錶

一:準備工作: 今天我們就來學習一下 ,怎麼用自定view繪製鐘錶? 在繪製鐘錶之前,我也看了好多部落格,上面寫的特別複雜,什麼計算公式一大堆,其實並不用這麼麻煩,只要我們瞭解了自定義view裡面的幾個屬性我們就可以用特別簡單的方法來繪製動態鐘錶,下面我們現在介紹一下這幾個屬性:

全程定義view繪製的一個開關器

我們在生活中總會用到一些東西,有一個東西來管理的 那就是開關 下面我們就寫一個自定義view繪製的開關了 下面就直接上程式碼了 public class KaiGuan extends View { boolean flag=true; priv

定義View繪製流程(面試專用)

(自己整理的比較亂,但這麼說沒問題的!) 自定義view是幹嘛的呢? 當我們不滿足於Android提供的原生控制元件和佈局時,就應該考慮到自定義view。 自定義View分為兩大塊。  自定義控制元件  和  自定義容器 自定義View必須重寫兩個構造方法  第一個

Android學習筆記之定義View

一、自定義View的分類 1.1.繼承 View 這種方法主要用於實現一些不規則的效果(不方便通過佈局的組合方式來實現),比如靜態或動態地顯示一些不規則的圖形(因此需要重寫onDraw方法)。值得注意的是,繼承View的自定義View需要自己制定 wrap_content

Android筆記--簡單的定義View繪控制元件

第一步:新建atts.xml檔案,自定義屬性,不引用系統的屬性,在構造器中使用安卓系統自帶的API的TypedArray類取出atts.xml中的自定義屬性使用(通過對映)。 第二步:新建一個類,繼承