探索 Android 自定義控件:基礎(chǔ)圖形

來(lái)自https://juejin.im/post/5d61514df265da03d60f0ab6#heading-6

[圖片上傳失敗...(image-5c215-1566990678513)]

前言

1. 文章內(nèi)容

這篇文章分為下面 5 個(gè)部分含思。

  1. 繪圖基礎(chǔ)

    這一節(jié)會(huì)介紹 Android 中的畫(huà)筆 Paint 和畫(huà)布 Canvas 的用法。

  2. 路徑繪制

    這一節(jié)會(huì)介紹 Android 中路徑 Path 的用法甘晤,包括直線含潘、弧線和雷達(dá)圖等圖形的繪制方法。

  3. 文字繪制

    這一節(jié)會(huì)介紹 Android 中繪制文字的方法线婚,包括粗體遏弱、斜體、加載字體等塞弊。

  4. 區(qū)域操作

    這一節(jié)會(huì)介紹 Android 中區(qū)域 Region 的用法漱逸,包括區(qū)域裁剪、區(qū)域合并等操作游沿。

  5. 畫(huà)布進(jìn)階

    這一節(jié)會(huì)對(duì)畫(huà)布的用法進(jìn)行更詳細(xì)的介紹饰抒,包括保存、指向恢復(fù)和圓形頭像奏候。

2. 注意事項(xiàng)

  • 對(duì)象創(chuàng)建

    下面的示例代碼會(huì)在 onDraw() 方法中創(chuàng)建 Paint循集、Path唇敞、Rect 和 Region等對(duì)象蔗草,這在實(shí)際開(kāi)發(fā)中是禁止的咒彤。

    因?yàn)楫?dāng) View 需要重繪時(shí)會(huì)調(diào)用 onDraw() 函數(shù),每一次調(diào)用 onDraw() 函數(shù)都會(huì)重新創(chuàng)建這些對(duì)象咒精。

    這樣會(huì)引起頻繁的 GC镶柱,嚴(yán)重時(shí)會(huì)導(dǎo)致 App 卡頓。

  • 圖片清晰度

    點(diǎn)擊文章中的圖片可以查看原圖模叙。

  • 示例代碼

    文中的示例代碼源碼在文章最下方可以找到歇拆。

1. 繪圖基礎(chǔ)

本節(jié)包含內(nèi)容如下。

  • 畫(huà)筆用法
  • 畫(huà)布用法
  • 顏色構(gòu)造

1.1 畫(huà)筆用法

我們這一節(jié)來(lái)看一下畫(huà)筆的用法范咨。

本節(jié)包含內(nèi)容如下故觅。

  • 設(shè)置畫(huà)筆顏色
  • 設(shè)置畫(huà)筆樣式
  • 設(shè)置畫(huà)筆寬度
  • 設(shè)置畫(huà)筆鋸齒

1.1.1 設(shè)置畫(huà)筆顏色

[圖片上傳失敗...(image-4cbe4a-1566990678513)]

Paint 的 setColor(int color) 方法可用于設(shè)置畫(huà)筆顏色,下面是 color 參數(shù)的取值渠啊。

一種顏色是由紅綠藍(lán)三色合成的输吏,所以 color 只能取 8 位 0xAARRGGBB 樣式顏色值。

  • 透明度

    A 表示透明度 Alpha替蛉,取值范圍是 0~255贯溅,值越小,圖像越透明

  • 紅色

    R 表示紅色 Red躲查,取值范圍是 0~255它浅,取值越小紅色越少

  • 綠色

    G 表示綠色 Green,取值范圍是 0~255镣煮,取值越小綠色越少

  • 藍(lán)色

    B 表示藍(lán)色 Blue姐霍,取值范圍是 0~255,取值越小藍(lán)色越少

除了手動(dòng)組合顏色怎静,系統(tǒng)還提供了一個(gè)用于解析顏色的類 Color邮弹,關(guān)于 Color 在后面會(huì)有更詳細(xì)的介紹。

1.1.2 設(shè)置畫(huà)筆樣式

[圖片上傳失敗...(image-270598-1566990678513)]

Paint 的 setStyle(Style style) 方法可用于設(shè)置畫(huà)筆樣式蚓聘,下面是 style 參數(shù)的取值腌乡。

  • 描邊

    • STROKE
  • 填充

    • FILL

    默認(rèn)樣式。

  • 描邊且填充

    • FILL_AND_STROKE

    描邊與填充疊加在一起顯示的效果夜牡,也就是這個(gè)值比填充多了一個(gè)描邊的寬度与纽。

1.1.3 設(shè)置畫(huà)筆寬度

Paint 的 setStrokeWidth(width) 方法用于設(shè)置描邊寬度,單位是 px塘装。

  • 注意事項(xiàng)

    當(dāng)畫(huà)筆的 Style 是 STROKE 或 FILL_AND_STROKE 時(shí)畫(huà)筆寬度才有意義急迂。

1.1.4 設(shè)置畫(huà)筆鋸齒

畫(huà)筆 Paint 繪制圖形時(shí)默認(rèn)不是抗鋸齒的,也就是邊邊會(huì)有鋸齒蹦肴。

Paint 提供了 setAntiAlias() 方法僚碎,這個(gè)方法可以開(kāi)啟畫(huà)筆的抗鋸齒功能。

下面是兩個(gè)放大后的圓阴幌,右邊的圓用的是抗鋸齒的畫(huà)筆繪制的勺阐。

[圖片上傳失敗...(image-a15b4b-1566990678513)]

1.2 畫(huà)布用法

上一節(jié)演示畫(huà)筆的同時(shí)也演示了畫(huà)布繪制圓的方法卷中,這一節(jié)我們來(lái)看一下畫(huà)布的其他方法。

本節(jié)內(nèi)容如下渊抽。

  • 設(shè)置背景
  • 繪制直線
  • 繪制點(diǎn)
  • 矩形結(jié)構(gòu)
  • 繪制矩形
  • 圓角矩形

1.2.1 設(shè)置背景

Canvas 提供了三個(gè)設(shè)置背景的方法蟆豫。

  • drawColor(int color)
  • drawARGB(int a, int r, int g, int b)
  • drawRGB(int r, int g, int b)

需要注意的是,設(shè)置畫(huà)布背景要在其他圖形繪制前設(shè)置懒闷,否則設(shè)置好的背景色會(huì)覆蓋原有的圖形十减。

[圖片上傳失敗...(image-e905b9-1566990678513)]

1.2.2 繪制直線

[圖片上傳失敗...(image-6424c4-1566990678513)]
Canvas 的 drawLine() 方法可以繪制直線,直線的粗細(xì)取決于 Paint 的 setStrokeWith(width) 中傳入的寬度愤估。

繪制直線需要注意的是帮辟,只有當(dāng) Style 是 STROKE、FILL_AND_STROKE 時(shí)繪制才有效玩焰。

  • drawLine(float startX, float starY, float stopX, float stopY, Paint paint)

1.2.3 繪制點(diǎn)

[圖片上傳失敗...(image-152094-1566990678513)]
Canvas 的 drawPoint() 方法可以用于繪制點(diǎn)织阅,點(diǎn)的大小取決于 setStrokeWith(width) 中傳入的寬度。

  • drawPoint(float x, float y, Paint paint)

1.2.4 矩形結(jié)構(gòu)

矩形結(jié)構(gòu)在繪制矩形區(qū)域的時(shí)候需要用到震捣。

Android 提供了 Rect 和 RectF 類用于存儲(chǔ)矩形數(shù)據(jù)結(jié)構(gòu)荔棉,下面是 Rect 和 RectF 的構(gòu)造函數(shù)。

[圖片上傳失敗...(image-1c2284-1566990678513)]

Rect 和 RectF 在于存儲(chǔ)的數(shù)據(jù)類型不同蒿赢。

  • Rect

    用于保存 int 類型數(shù)值的矩形結(jié)構(gòu)

  • RectF

    用于保存 float 類型數(shù)值的矩形結(jié)構(gòu)

1.2.5 繪制矩形

[圖片上傳失敗...(image-3b5c2a-1566990678513)]
Canvas 的 drawPoint() 和 drawRect() 方法都可用于繪制矩形润樱。

下面是這兩個(gè)方法的區(qū)別。

  • 形狀

    • drawPoint()

      只能指定矩形中心的坐標(biāo)羡棵,只能畫(huà)出正方形壹若。

    • drawRect()

      需要指定矩形左上和右下兩個(gè)點(diǎn)的位置,可以是長(zhǎng)方形皂冰。

  • 樣式

    • drawPoint()

      只能是填充樣式店展。

    • drawRect()

      可以自己選擇樣式,可以是描邊也可以是填充秃流。

下面是 Canvas 中提供用于繪制矩形的三個(gè)方法赂蕴。

  • drawRect(float left, float top, float right, float bottom, Paint paint)
  • drawRect(RectF rect, Paint paint)
  • drawRect(Rect r, Paint paint)

1.2.6 圓角矩形

Canvas 中提供了一個(gè) drawRoundRect 方法用于繪制圓角矩形,圓角矩形的四個(gè)角是橢圓的一角舶胀,下面是它的基本用法概说。

[圖片上傳失敗...(image-406e14-1566990678513)]

1.3 顏色構(gòu)造

Color 類是 Android 中與顏色有關(guān)的類。

本節(jié)內(nèi)容如下嚣伐。

  • 顏色常量
  • 構(gòu)造顏色

1.3.1 顏色常量

Color 中定義了下面的顏色常量值糖赔。

[圖片上傳失敗...(image-48c6cd-1566988049043)]

1.3.2 構(gòu)造顏色

除了顏色常量外,Color 還提供了一些構(gòu)造顏色的方法轩端。

[圖片上傳失敗...(image-5ad560-1566988049043)]

alpha << 就是進(jìn) 24 位放典,當(dāng)我們調(diào)用 Color.argb(255, 0, 0,0 0) 時(shí),轉(zhuǎn)換后的 16 進(jìn)制顏色值就是 0xFF000000。

[圖片上傳失敗...(image-dd67eb-1566988049043)]

2. 路徑繪制

路徑 Path 指的是畫(huà)筆畫(huà)出來(lái)的一條不間斷的曲線奋构,本節(jié)會(huì)講解直線和弧線路徑骨田,除了這兩種方式外還有很多方法可以實(shí)現(xiàn)很多效果。

drawPath 是 Canvas 繪制路徑的方法声怔。

  • drawPath(Path path, Paint paint)

本節(jié)內(nèi)容如下。

  1. 直線路徑
  2. 弧線路徑
  3. 添加路徑
  4. 填充路徑
  5. 重置路徑
  6. 雷達(dá)路徑

2.1 直線路徑

[圖片上傳失敗...(image-324557-1566988049043)]

上面是一段繪制直線路徑的代碼舱呻,這里需要注意的是醋火,上面代碼中的畫(huà)筆樣式設(shè)為描邊,默認(rèn)是填充的箱吕。

也就是在默認(rèn)情況下芥驳,多條線相連形成閉環(huán)后,中間的區(qū)域會(huì)被填充茬高。

繪制直線路徑涉及:起點(diǎn)兆旬、終點(diǎn)和閉環(huán)。

  • 起點(diǎn)

    Path 的 moveTo() 用于指定直線路徑的起點(diǎn)怎栽,參數(shù) x1 和 y1 是起點(diǎn)坐標(biāo)值丽猬。

    • moveTo(float x1, float y1)
  • 終點(diǎn)

    Path 的 lineTo() 用于指定直線路徑的起點(diǎn),參數(shù) x2 和 y2 是終點(diǎn)坐標(biāo)值熏瞄,也是下一次繪制直線的起點(diǎn)脚祟。

    • lineTo(float x2, float y2)
  • 閉環(huán)

    Path 的 close() 方法用于形成閉環(huán)。

    • close()

    如果連續(xù)畫(huà)了幾條直線强饮,但沒(méi)有形成閉環(huán)由桌,調(diào)用 close() 函數(shù)會(huì)把路徑首尾連接起來(lái)形成閉環(huán),相當(dāng)于是幫我們畫(huà)多一條直線邮丰。

    如果只畫(huà)了一條直線行您,那 close() 方法是不會(huì)起作用的。

2.2 弧線路徑

Path 的 arcTo() 方法可用于繪制弧線剪廉,弧線在這里指的是橢圓上截取的一部分娃循。

  • arcTo(RectF oval, float startAngle, sweepAngle)

本節(jié)內(nèi)容如下。

  • 弧線樣式
  • 弧線起點(diǎn)
  • 弧線角度
  • 弧線函數(shù)

2.2.1 弧線樣式

這里的橢圓底色默認(rèn)是不存在的斗蒋,在這里畫(huà)出來(lái)主要是為了突出弧線淮野。

在這里我們要注意的是,弧線默認(rèn)是填充的吹泡,更準(zhǔn)確的來(lái)說(shuō) drawArc() 方法是切出橢圓中的一塊骤星。

如果我們只想要一條線的話,就要自己設(shè)置描邊樣式和描邊寬度爆哑。

[圖片上傳失敗...(image-9a09fc-1566988049043)]

2.2.2 弧線起點(diǎn)

除了樣式以外洞难,繪制弧線要注意的另外一點(diǎn)就是起點(diǎn)。

  • 改變起點(diǎn)

    如果我們調(diào)用了 moveTo() 改變了路徑的起點(diǎn)揭朝,那弧線就會(huì)從 moveTo() 接收到的坐標(biāo)開(kāi)始繪制队贱。

  • 重置起點(diǎn)

    如果我們想重置起點(diǎn)到弧線正常該開(kāi)始的位置色冀,我們可以把 forceMoveTo 設(shè)為 true。

[圖片上傳失敗...(image-e83d85-1566988049043)]

2.2.3 弧線角度

arcTo 中有兩個(gè)跟角度有關(guān)的參數(shù) startAngle 和 sweepAngle柱嫌,這兩個(gè)參數(shù)分別代表起始角和掃描角锋恬。

  • 起始角

    起始角指定弧線從哪里開(kāi)始畫(huà)起。

  • 掃描角

    掃描角可以看成是弧線的長(zhǎng)度编丘。

[圖片上傳失敗...(image-c5c230-1566988049043)]

2.2.4 弧線函數(shù)

[圖片上傳失敗...(image-bc106-1566988049043)]

Path 中定義了的三個(gè) arcTo() 函數(shù)与学,下面是 arcTo() 函數(shù)中主要四個(gè)參數(shù)的含義。

  • oval

    生成橢圓的矩形

  • startAngle

    弧開(kāi)始的角度嘉抓,以 X 軸正方向?yàn)?0°

  • sweepAngle

    弧持續(xù)的角度

  • forceMoveTo

    重置起點(diǎn)索守,把繪制弧線的起點(diǎn)從 moveTo 的坐標(biāo)重置到 startAngle 的位置。

2.3 添加路徑

本節(jié)內(nèi)容如下抑片。

  • 路徑添加方法
  • 路徑繪制方向

2.3.1 路徑添加方法

Path 提供了 addXXX 函數(shù)用于添加路徑卵佛,添加的路徑可以是不連續(xù)的,還可以是曲線敞斋。

下面是 Path 中提供的一些添加路徑的方法截汪。

[圖片上傳失敗...(image-afc2b1-1566988049043)]

下面是添加路徑的示例。

[圖片上傳失敗...(image-2ae3dd-1566988049043)]

2.3.2 路徑繪制方向

在添加路徑的函數(shù)中有一些函數(shù)有 Direction 參數(shù)植捎,這個(gè) Direction 就是繪制的方向挫鸽。

方向分為順時(shí)針逆時(shí)針 CCW(Counter-Clockwise)。

[圖片上傳失敗...(image-294b7d-1566988049043)]

下面是不同方向的繪制示例鸥跟,這個(gè)示例中用到了 drawTextOnPath 方法丢郊,這個(gè)方法在講繪制文字的時(shí)候會(huì)有更詳細(xì)的介紹,現(xiàn)在我們先看繪制方向?qū)L制效果的影響医咨。

[圖片上傳失敗...(image-7b16ad-1566988049043)]

2.4 填充路徑

路徑 Path 的填充模式與畫(huà)筆 Paint 的填充模式不同枫匾,Path 的填充模式是指填充 Path 的哪部分。

在 Path 中有一個(gè) FillType 枚舉類拟淮,其中定義了 4 種填充類型干茉。

[圖片上傳失敗...(image-84560-1566988049043)]

下面是這四種填充類型的示例。

[圖片上傳失敗...(image-b4dbd9-1566988049043)]

2.5 重置路徑

Android 提供了兩個(gè)重置路徑的方法很泊,讓我們可以重復(fù)使用 Path 對(duì)象角虫。

路徑 Path 一旦被重置,其中保存的所有路徑都會(huì)被清空委造,這樣就不需要重新創(chuàng)建一個(gè) Path 對(duì)象了戳鹅。

  • reset()

    reset() 函數(shù)類似于新建一個(gè)路徑對(duì)象,除了填充類型 FillType 以外昏兆,Path 的所有數(shù)據(jù)都會(huì)被回收并重新分配枫虏。

  • rewind()

    rewind() 函數(shù)會(huì)清除 FillType 和所有的路徑,保留內(nèi)部數(shù)據(jù)結(jié)構(gòu),以便更快地重用隶债。

    比如我們需要重復(fù)繪制一類線段腾它,它們的點(diǎn)和數(shù)量相等,使用 rewind() 函數(shù)可以保留裝載點(diǎn)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)死讹,效率更高瞒滴。

    要注意的是,只有重復(fù)繪制相同路徑時(shí)赞警,這些數(shù)據(jù)結(jié)構(gòu)才是可復(fù)用的妓忍。

2.6 雷達(dá)路徑

本節(jié)包含如下內(nèi)容。

  1. 創(chuàng)建畫(huà)筆
  2. 計(jì)算圓心
  3. 畫(huà)多邊形
  4. 畫(huà)網(wǎng)格線
  5. 畫(huà)數(shù)據(jù)圖

2.6.1 創(chuàng)建畫(huà)筆

[圖片上傳失敗...(image-af718b-1566988049043)]

2.6.2 計(jì)算圓心

在控件大小發(fā)生變化時(shí)仅颇,onSizeChanged() 會(huì)被回調(diào)并得到最新的控件大小,所以我們需要重寫這個(gè)方法碘举。

網(wǎng)狀路徑的大小占當(dāng)前控件的 90%忘瓦,所以半徑為:寬高最小值 ÷ 2 × 0.9。

然后根據(jù)中心點(diǎn)引颈,分別繪制雷達(dá)網(wǎng)格耕皮、網(wǎng)格中線、數(shù)據(jù)圖蝙场。

[圖片上傳失敗...(image-790871-1566988049043)]

2.6.3 畫(huà)多邊形

drawPolygon 涉及到三角函數(shù)凌停,下面是公式計(jì)算示意圖。

[圖片上傳失敗...(image-7650f6-1566988049043)]

下面是公式的具體實(shí)現(xiàn)售滤。

[圖片上傳失敗...(image-2b516d-1566988049043)]

2.6.4 畫(huà)網(wǎng)格線

[圖片上傳失敗...(image-8ff185-1566988049043)]

2.6.5 畫(huà)數(shù)據(jù)圖

[圖片上傳失敗...(image-2b881b-1566988049043)]

3. 文字繪制

本文包含如下內(nèi)容罚拟。

  • 畫(huà)筆文字參數(shù)
  • 畫(huà)布繪制文字
  • 設(shè)置字體樣式
  • 獲取文字寬高

3.1 畫(huà)筆文字參數(shù)

本節(jié)包含內(nèi)容如下。

  • 文字參數(shù)
  • 文字樣式
  • 文字對(duì)齊
  • 文字變形
  • 其他設(shè)置

3.1.1 文字參數(shù)

下面是幾個(gè) Paint 中設(shè)置文字繪制效果的方法完箩。

[圖片上傳失敗...(image-474383-1566988049043)]

3.1.2 文字樣式

[圖片上傳失敗...(image-989051-1566988049043)]

3.1.2 文字對(duì)齊

我們可以通過(guò) Paint 的 setTextAlign(align) 方法來(lái)設(shè)置繪制文字時(shí)的對(duì)齊方向赐俗。

Paint 中有一個(gè)枚舉類 Align,在 Align 中定義了三種對(duì)齊模式:LEFT弊知、CENTER阻逮、RIGHT,這三種模式分別代表左對(duì)齊秩彤,居中對(duì)齊和右對(duì)齊叔扼。

[圖片上傳失敗...(image-62fdf1-1566988049043)]

3.1.4 文字變形

[圖片上傳失敗...(image-4209a-1566988049043)]

3.1.6 其他設(shè)置

[圖片上傳失敗...(image-8a030a-1566988049043)]

3.2 畫(huà)布繪制文字

上一節(jié)我們看到了Canvas 的 drawText() 方法,下面我們來(lái)看一下 Canvas 提供的其他繪制文本的方法漫雷。

本節(jié)包含內(nèi)容如下瓜富。

  • 逐字繪制文字
  • 路徑繪制文字

3.2.1 逐字繪制文字

[圖片上傳失敗...(image-3fbbdc-1566988049043)]

3.2.2 路徑繪制文字

在講解路徑繪制方向時(shí)我們就已經(jīng)用到過(guò) Canvas 提供了 drawTextOnPath() 方法,在這里我們看一下這個(gè)方法中的偏移參數(shù)降盹。

[圖片上傳失敗...(image-ae12ea-1566988049043)]

3.3 設(shè)置字體樣式

Paint 中提供了 setTypeFace(typeFace) 方法同于設(shè)置字體樣式食呻。

TypeFace 是專門用于設(shè)置字體樣式的,我們可以指定系統(tǒng)提供的字體也可以指定自定義字體。

當(dāng)創(chuàng)建 TypeFace 類時(shí)仅胞,可以指定是正常字體每辟、斜體或者粗體,當(dāng)指定樣式中沒(méi)有相關(guān)文字的樣式時(shí)干旧,就會(huì)用系統(tǒng)默認(rèn)的樣式顯示渠欺,一般默認(rèn)是宋體。

本節(jié)包含如下內(nèi)容椎眯。

  • 系統(tǒng)字體
  • 字體樣式
  • 加載字體

3.3.1 系統(tǒng)字體

TypeFace 中提供了下面三種字體挠将,這三種字體對(duì)中文的支持不是很好,當(dāng)遇到不支持的文字時(shí)编整,會(huì)用系統(tǒng)默認(rèn)字體來(lái)寫舔稀。

[圖片上傳失敗...(image-79588b-1566988049043)]

下面是這三種字體的顯示效果。

[圖片上傳失敗...(image-ab18cf-1566988049043)]

3.3.2 字體樣式

除了可以選擇特定字體以外掌测,我們還可以通過(guò) defaultFromStyle() 方法選擇特定具體的某種樣式内贮。

TypeFace 中還定義了下面四種字體樣式。

[圖片上傳失敗...(image-763a48-1566988049043)]

下面是這四種樣式的顯示效果汞斧。

[圖片上傳失敗...(image-3ac806-1566988049043)]

3.3.3 加載字體

Android 提供了下面三種加載自定義字體的方式夜郁。

  • 根據(jù)字體名加載
  • 根據(jù)資源名加載
  • 根據(jù)文件名加載

1. 根據(jù)字體名加載

TypeFace 中提供了一個(gè)用于根據(jù)字體名加載字體的 create() 方法,比如下面這行代碼這樣粘勒。

由于模擬器上沒(méi)有別的字體竞端,在這里就不演示了,大家有興趣的可以自己嘗試下庙睡。

[圖片上傳失敗...(image-db9163-1566988049043)]

2. 根據(jù)資源名加載

假如我們從網(wǎng)上下了個(gè) ttf 字體文件事富,想放在包中直接使用,我們可以在 app/src/main 目錄下建一個(gè) assets 目錄乘陪,再建一個(gè) fonts 目錄赵颅,然后把 ttf 文件放到里面。

而根據(jù)資源名加載字體的方式就是 TypeFace 的 createFromAsset() 方法暂刘。

[圖片上傳失敗...(image-b39454-1566988049043)]

3. 根據(jù)文件名加載字體

從資源中加載字體的弊端就是會(huì)讓 APK 包變大饺谬,如果我們把字體下載到本地的話就可以避免這個(gè)問(wèn)題。

[圖片上傳失敗...(image-f8a7db-1566988049043)]

3.4 獲取文字寬高

Paint 提供了三種獲取文字寬高的方法谣拣,下面我們來(lái)看一下這幾個(gè)方法的用法募寨。

本節(jié)內(nèi)容如下。

  • 獲取字體寬度
  • 獲取字體寬高

3.4.1 獲取字體寬度

[圖片上傳失敗...(image-134278-1566988049043)]

3.4.2 獲取字體寬高

[圖片上傳失敗...(image-fa0125-1566988049043)]

4. 區(qū)域操作

區(qū)域指的是 Region 類森缠,Region 是一塊任意形狀的封閉圖形拔鹰,這一節(jié)我們來(lái)看一下 Region 提供的一些操作區(qū)域的方法。

本節(jié)包含如下內(nèi)容。

  1. 創(chuàng)建區(qū)域
  2. 合并區(qū)域
  3. 裁剪區(qū)域
  4. 其他操作

4.1 創(chuàng)建區(qū)域

直接構(gòu)造區(qū)域指的是用 Region 的構(gòu)造函數(shù)創(chuàng)建區(qū)域,下面是 Region 的四個(gè)構(gòu)造函數(shù)工腋。

[圖片上傳失敗...(image-1e84ed-1566988049043)]

下面是一個(gè)繪制 Region 的簡(jiǎn)單示例勾哩,由于 Canvas 中沒(méi)有繪制 Region 的方法,所以我們?cè)谶@里自己定義一個(gè) drawRegion() 方法來(lái)繪制 Region糠涛。

Region 可用于繪制各種各樣的形狀贺拣,我們先看一下怎么繪制一個(gè)簡(jiǎn)單的正方形 Region鸦难。

[圖片上傳失敗...(image-da5147-1566988049043)]

4.2 合并區(qū)域

Region 提供了一個(gè) union(rect) 函數(shù)欧聘,傳入目標(biāo)矩陣到 union 函數(shù)中就能實(shí)現(xiàn)合并區(qū)域片林。

[圖片上傳失敗...(image-539c3-1566988049043)]

4.3 裁剪區(qū)域

Region 中聲明了下面的 5 個(gè)設(shè)置區(qū)域的方法。

[圖片上傳失敗...(image-e9cffc-1566988049043)]

裁剪區(qū)域需要先創(chuàng)建一個(gè)空 Region怀骤,然后調(diào)用 setPath 方法费封,下面是裁剪區(qū)域的操作,橢圓路徑和裁剪區(qū)域相交的區(qū)域就是裁剪結(jié)果蒋伦。

[圖片上傳失敗...(image-f9adb8-1566988049043)]

4.4 其他操作

本節(jié)如下內(nèi)容弓摘。

  • 集合運(yùn)算方法
  • 集合運(yùn)算類型
  • 集合運(yùn)算示例

1. 集合運(yùn)算方法

除了 union 以外,Region 還提供了下面幾個(gè)區(qū)域操作方法痕届,而且 union 本身也是調(diào)用了 op 方法韧献。

[圖片上傳失敗...(image-8dfcea-1566988049043)]

2. 集合運(yùn)算類型

在上面這些方法中比較重要的是 Op 參數(shù),Op 是 Region 中定義的枚舉類爷抓,是集合運(yùn)算操作势决。

在這里阻塑,集合中的元素就是 Region 矩陣范圍中的子矩陣蓝撇。

[圖片上傳失敗...(image-2e85ed-1566988049043)]

**3. 集合運(yùn)算示例 **

下面是這些集合運(yùn)算的示例。

[圖片上傳失敗...(image-d1f254-1566988049043)]

5. 畫(huà)布

上一節(jié)我們講了怎么用畫(huà)布 Canvas 繪制各種圖形陈莽,畫(huà)布除了能用來(lái)繪制各種圖形以外渤昌,我們還能對(duì)畫(huà)筆進(jìn)行變換和裁剪。

本節(jié)內(nèi)容如下走搁。

  1. 畫(huà)布平移
  2. 畫(huà)布合成
  3. 畫(huà)布裁剪
  4. 畫(huà)布保存

4.1 畫(huà)布平移

畫(huà)布 Canvas 提供了一個(gè)可用于平移的方法 translate()独柑,畫(huà)布的原始狀態(tài)是以左上角為圓點(diǎn),向右是 X 軸正方向私植,向下是 Y 軸正方向忌栅。

由于畫(huà)布的左上角是坐標(biāo)軸的原點(diǎn)(0, 0),所以平移畫(huà)布后曲稼,坐標(biāo)系也會(huì)被平移索绪。

平移后的畫(huà)筆的左上角是新的坐標(biāo)原點(diǎn)。

[圖片上傳失敗...(image-34e63f-1566988049043)]

4.2 畫(huà)布合成

合成畫(huà)布與屏幕的操作是由系統(tǒng)進(jìn)行的贫悄,這一節(jié)我們來(lái)看一下這個(gè)操作的簡(jiǎn)單介紹瑞驱。

本節(jié)內(nèi)容如下。

  • 合成
  • 平移
  • 小結(jié)

4.2.1 合成

我們每次在畫(huà)布上畫(huà)圖時(shí)窄坦,系統(tǒng)會(huì)先產(chǎn)生一個(gè)透明圖層唤反,在這個(gè)圖層上畫(huà)圖凳寺,花完后再覆蓋在屏幕上。

[圖片上傳失敗...(image-91e892-1566988049043)]

4.2.2 平移

當(dāng)我們繪制紅色矩形時(shí)彤侍,會(huì)產(chǎn)生另一個(gè)新的 Canvas 透明圖層肠缨,此時(shí)畫(huà)布坐標(biāo)改變了,所以繪圖方式如下圖所示拥刻。

由于 Canvas 已經(jīng)平移了 350 像素怜瞒,所以畫(huà)圖時(shí)是以新原點(diǎn)來(lái)產(chǎn)生視圖的,然后再合成到屏幕上般哼。

當(dāng)屏幕移動(dòng)后吴汪,有一部分超出屏幕的范圍,超出范圍的圖像是不顯示的蒸眠。

[圖片上傳失敗...(image-8fb2a4-1566988049043)]

4.2.3 小結(jié)

使用 Canvas 的繪制方法有下面三個(gè)需要注意的點(diǎn)漾橙。

  1. 生成新圖層

    每次調(diào)用繪制方法 drawXXX 時(shí),都會(huì)產(chǎn)生一個(gè)新的 Canvas 透明圖層楞卡。

  2. 操作不可逆

    調(diào)用了繪制方法前霜运,平移和旋轉(zhuǎn)等函數(shù)對(duì) Canvas 進(jìn)行了操作,那么這個(gè)操作是不可逆的蒋腮,每次產(chǎn)生的畫(huà)布的最新位置都是這些操作后的位置淘捡。

  3. 超出不顯示

    在 Canvas 圖層與屏幕合成時(shí),超出屏幕范圍的圖像是不會(huì)顯示出來(lái)的

4.3 畫(huà)布裁剪

畫(huà)布裁剪是指用 Canvas 的 clipXXX 函數(shù)與矩形池摧、路徑和區(qū)域取交焦除、并、差等集合運(yùn)算來(lái)獲得最新的畫(huà)布形狀作彤。

除非使用了保存和恢復(fù)函數(shù)膘魄,否則裁剪操作是不可逆的,也就是一旦裁剪就無(wú)法恢復(fù)竭讳。

在 Canvas 中定義了下面幾個(gè)裁剪函數(shù)创葡。

[圖片上傳失敗...(image-634002-1566988049043)]

下面是一個(gè)裁剪示例。

[圖片上傳失敗...(image-88156e-1566988049043)]

4.4 畫(huà)布保存

在前面我們說(shuō)到了畫(huà)布的操作是不可逆的绢慢,這會(huì)造成很多麻煩灿渴。

比如為了實(shí)現(xiàn)一些效果需要對(duì)畫(huà)布進(jìn)行操作,但畫(huà)布狀態(tài)改變后又影響了后面的繪制效果胰舆。

因?yàn)檫@個(gè)原因骚露,畫(huà)布提供了保存和恢復(fù)功能,這兩個(gè)功能對(duì)應(yīng)的方法是 save() 和 restore()思瘟,每調(diào)用一次 save() 就會(huì)把當(dāng)前畫(huà)布狀態(tài)保存到棧中荸百。

本節(jié)內(nèi)容如下。

  • 多次保存
  • 指向恢復(fù)
  • 圓形頭像

4.4.1 多次保存

畫(huà)布單次保存恢復(fù)的操作比較簡(jiǎn)單滨攻,我們來(lái)看一下畫(huà)布多次保存和多次恢復(fù)的效果够话。

[圖片上傳失敗...(image-e1ce9e-1566988049043)]

4.4.2 指向恢復(fù)

指向恢復(fù)指的是恢復(fù)到特定的狀態(tài)蓝翰,比如我們上面這個(gè)例子,假如我們要恢復(fù)到藍(lán)色400女嘲,那我們要調(diào)用三次 resoter()畜份。

為了解決這個(gè)問(wèn)題,Canvas 提供了另一個(gè)恢復(fù)畫(huà)布狀態(tài)的函數(shù) restoreToCount(count)欣尼,下面我們來(lái)看一下這個(gè)函數(shù)的用法爆雹。

[圖片上傳失敗...(image-62f1eb-1566988049043)]

4.4.3 圓形頭像

下面我們來(lái)看一下怎么用畫(huà)布的保存和恢復(fù)功能實(shí)現(xiàn)繪制圓形頭像后,再把畫(huà)布恢復(fù)回來(lái)愕鼓。

本節(jié)包含如下內(nèi)容钙态。

  • 初始化
  • 繪制頭像
  • 去除鋸齒

1. 初始化

這里之所以要禁用硬件加速,是因?yàn)橛布铀偈鞘褂玫?OpenGL 函數(shù)完成實(shí)際繪制菇晃,而 OpenGL 并不能完全支持原始繪制函數(shù)册倒,比如 clipPath() 在開(kāi)啟硬件加速的情況下只有在 API 18 以上的系統(tǒng)才會(huì)生效。

[圖片上傳失敗...(image-a8b7d4-1566988049043)]
2. 繪制頭像

[圖片上傳失敗...(image-93fe0f-1566988049043)]
3. 去除鋸齒

clipPath 實(shí)現(xiàn)的圓形圖像是有鋸齒的磺送,我們可以用 PorterDuffXfermode 來(lái)實(shí)現(xiàn)無(wú)鋸齒的圓形圖片驻子。

[圖片上傳失敗...(image-f38436-1566988049043)]

. 代碼
https://github.com/zeshaoaaa/AndroidCustomView

作者:燈不利多
鏈接:https://juejin.im/post/5d61514df265da03d60f0ab6
來(lái)源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)估灿,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處崇呵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市馅袁,隨后出現(xiàn)的幾起案子域慷,更是在濱河造成了極大的恐慌,老刑警劉巖司顿,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芒粹,死亡現(xiàn)場(chǎng)離奇詭異兄纺,居然都是意外死亡大溜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門估脆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钦奋,“玉大人,你說(shuō)我怎么就攤上這事疙赠「恫模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵圃阳,是天一觀的道長(zhǎng)厌衔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)捍岳,這世上最難降的妖魔是什么富寿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任睬隶,我火速辦了婚禮,結(jié)果婚禮上页徐,老公的妹妹穿的比我還像新娘苏潜。我一直安慰自己,他們只是感情好变勇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布恤左。 她就那樣靜靜地躺著,像睡著了一般搀绣。 火紅的嫁衣襯著肌膚如雪飞袋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天链患,我揣著相機(jī)與錄音授嘀,去河邊找鬼。 笑死锣险,一個(gè)胖子當(dāng)著我的面吹牛蹄皱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芯肤,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼巷折,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了崖咨?” 一聲冷哼從身側(cè)響起锻拘,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎击蹲,沒(méi)想到半個(gè)月后署拟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歌豺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年推穷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片类咧。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馒铃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痕惋,到底是詐尸還是另有隱情区宇,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布值戳,位于F島的核電站议谷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏堕虹。R本人自食惡果不足惜卧晓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一叶洞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧禀崖,春花似錦衩辟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至掸屡,卻和暖如春封寞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仅财。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工狈究, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盏求。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓抖锥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親碎罚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子磅废,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 前言 1. 文章內(nèi)容 這篇文章分為下面 5 個(gè)部分。 繪圖基礎(chǔ)這一節(jié)會(huì)介紹 Android 中的畫(huà)筆 Paint ...
    燈不利多閱讀 2,352評(píng)論 4 26
  • 畫(huà)布canvas 畫(huà)布是一個(gè)矩形區(qū)域荆烈,我們可以控制其每一像素來(lái)繪制我們想要的內(nèi)容 canvas 擁有多種繪制點(diǎn)拯勉、線...
    秋分落葉閱讀 1,066評(píng)論 0 1
  • 一、概述 1. 四線格與基線 小時(shí)候憔购,我們?cè)趧傞_(kāi)始學(xué)習(xí)寫字母時(shí)宫峦,用的本子是四線格的,我們必須把字母按照規(guī)則寫在四線...
    addapp閱讀 7,613評(píng)論 2 17
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程玫鸟,因...
    小菜c閱讀 6,358評(píng)論 0 17
  • 完形修習(xí)Day2-內(nèi)在感受 練習(xí)二:現(xiàn)在导绷,你去接觸另外一個(gè)人,TA或許是你的同事鞋邑、領(lǐng)導(dǎo)诵次、愛(ài)人账蓉、孩子枚碗、學(xué)生等等,不加...
    Vivi_huang閱讀 231評(píng)論 0 1