最近要弄一個透明的圓形的一個覆蓋view,這個平時做應用的時候經常需要用到。如下圖所示:

我想大多數人平時的用法就是要設計出一張這樣的圖片,這樣簡單省事,但是也有個難題就是這個圖片是死的,中間部分的透明圓不能移動。
我整理了下面的四種方法,
一、就是上面說的用圖片
這種方法就是圖片是死的不方便移動。
二、就是自己畫,(這種方式應該說是最簡單了,還可以隨心所欲的變動)
自定義一個透明背景的view,在view上畫出一個圓
下面說實現

如果你需要一個半徑為b的透明圓,實現如下
首先定義畫筆Paint mPaint = new Paint();
然后定義你想要的顏色
mPaint.setAntiAlias(true);
mPaint.setColor(ContextCompat.getColor(context, R.color.jasper));
mPaint.setStyle(Paint.Style.STROKE);
再定義你畫筆的寬度mPaint.setStrokeWidth(a+b);
a是圓據頂部的高度,b是圓的半徑,實際上就是這個畫布高度的一半
重點來了
你如果就這么canvas.drawCircle(x, y, b, mPaint);畫圓,那你得到的圓的大小肯定不對,這個時候圓的半徑需要擴大,才能得到你想要的半徑是b的圓,那怎么擴大呢?
實際上就是將半徑的大小變?yōu)樵镜陌霃酱笮〖由袭嫻P寬度的一半。即 raduis=b + (a+b)/2
然后canvas.drawCircle(x, y, raduis, mPaint);這樣畫出的圓的半徑才是b。
這樣做的好處是你想將圓畫在哪里都可以,也可以是其他的任何形狀。
三、也是畫,根據網友說的,取path差集就可以
定義畫筆
val mPaint = Paint()
mPaint.isAntiAlias = true
mPaint.color = ContextCompat.getColor(context!!, R.color.colorWhite)
mPaint.style = Paint.Style.FILL
mPaint.strokeWidth = 5f
然后開畫,定義兩個path,mPath和mPath1.
var mPath = Path()
var mPath1 = Path()
val rectf = RectF(0F, 0F, getDisplayWidth().toFloat(), getDisplayHeight().toFloat())
mPath.addRect(rectf, Path.Direction.CW)
mPath1.addCircle(x, y, mRadius, Path.Direction.CW)
val path = mPath.minus(mPath1)//取差集
canvas?.drawPath(path, mPaint)
四、還是畫,這種方式復雜點
定義畫筆將圓之外的部分畫滿,留下圓不畫,那就是了。這需要用path實現。
首先一樣是定義畫筆
val mPaint = Paint()
mPaint.isAntiAlias = true
mPaint.color = ContextCompat.getColor(context!!, R.color.colorWhite)
mPaint.style = Paint.Style.FILL
mPaint.strokeWidth = 5f
隨后開始畫,例如我的圓心在寬度的中間,
mPath.moveTo(getDisplayWidth() / 2 - mRadius, mMarginTop + mRadius)//第一個點在圓心左側的邊緣
mPath.lineTo(0F, mMarginTop + mRadius)//第二個點橫移到最左側
mPath.lineTo(0F, 0F)//第三個點到屏幕左上角
mPath.lineTo((getDisplayWidth() / 2).toFloat(), 0F)//第四個點到圓心的正上方,屏幕的最頂端
mPath.lineTo((getDisplayWidth() / 2).toFloat(), mMarginTop.toFloat())//第五個點圓心上方,圓的邊緣
mPath.cubicTo((getDisplayWidth() / 2).toFloat(), mMarginTop.toFloat(),
getDisplayWidth() / 2 - mRadius, mMarginTop.toFloat(),
getDisplayWidth() / 2 - mRadius,
mMarginTop + mRadius
)//利用貝塞爾曲線來畫半圓
canvas?.drawPath(mPath, mPaint)
畫出來的效果

總共要畫四個這樣的部分,其實畫出來后也不是那么圓,還是要在變化在畫上一個稍微寬一點的圓,這比較麻煩,建議使用第二種。
四、其實還有一種方法,但是這種方法對布局有要求,有缺陷下面會講
比如我上一篇 一個非常好用的頁面引導工具guideView
這里面就是畫的一個透明的圖形。
首先是定義畫筆
mPaint.isAntiAlias = true
mPaint.style = Paint.Style.FILL_AND_STROKE
mPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
然后直接畫出一想要的形狀即可canvas?.drawCircle(x,y,mRaduis,mPaint)
你還可以定義一個半透明的背景setBackgroundColor(ContextCompat.getColor(context!!, R.color.translucence))
這樣定義出來的view直接就有那個效果。但是這個view我直接放在layout中是不行的,畫出來的是一個黑色不透明的圖形,只有將這個view放在popupwindow或者dialog中時起作用。(這里目前我也不知道為什么,我嘗試將所有的activity都變成透明的背景,但還是一樣都是不起作用)
我想上面三種方法已經夠用了,晚點我打成一個庫,可以通過設置padding、margin、半徑、或者圖形選擇來畫出任何位置的任何圖形的透明圖片,現在沒時間,有個項目正在催。
好了,今天就到這里。上面的方法不滿意,請看下篇,絕對畫法,能支持到api14,包你滿意