Jetpack?Compose?Canvas繪制超詳細(xì)介紹
1. Canvas
@Composable fun Canvas( modifier: Modifier, onDraw: DrawScope.() -> Unit ) = Spacer(modifier.drawBehind(onDraw))
modifier
:這里主要作用是指定畫(huà)布的大小。onDraw
就是執(zhí)行具體的繪制??梢钥吹剿峁┝艘粋€(gè)繪圖環(huán)境的作用域DrawScope
,這里提供有我們經(jīng)常使用的繪圖api和屬性,比如drawLine
、size
等。
先來(lái)一個(gè)簡(jiǎn)單的例子看看如何使用:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
畫(huà)一條線,開(kāi)始和結(jié)束位置分別是畫(huà)布的右上角和左下角。效果如下:
2. 繪制方法
1. drawLine
drawLine
在上面的例子中簡(jiǎn)單說(shuō)明了,當(dāng)然它不止這些功能。
fun drawLine( color: Color, //或 brush: Brush, start: Offset, end: Offset, strokeWidth: Float = Stroke.HairlineWidth, cap: StrokeCap = Stroke.DefaultCap, pathEffect: PathEffect? = null, /*FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
- 指定線的顏色用
color
- 漸變色可以使用
brush
,本系列第三篇有說(shuō)明。 strokeWidth
是線的寬度,默認(rèn)是1px。cap
是線頭的形狀,默認(rèn)是StrokeCap.Butt
平頭。還有StrokeCap.Round
圓頭,StrokeCap.Square
方頭。這部分和Android中的Paint是一樣的。平頭和方頭的不同在于是否延伸出來(lái)的部分。
pathEffect
是線段的效果,比如虛線這種就是使用PathEffect.dashPathEffect(intervals: FloatArray, phase: Float = 0f)
,舉一個(gè)例子:
PathEffect.dashPathEffect(floatArrayOf(20f, 10f), 10f)
intervals
中的20f表示虛線的寬度,10f是間隔寬度。phase
的10f表示初始的偏移距離。所以一開(kāi)始偏移10f,就會(huì)導(dǎo)致第一段的線段被"裁剪"10f,具體效果如下圖:
alpha
是線段的透明度。colorFilter
是顏色過(guò)濾器,本系列第四篇有說(shuō)明,這里就不重復(fù)介紹了。blendMode
:混合模式。這個(gè)不在本篇的范圍內(nèi),后面有機(jī)會(huì)我會(huì)詳細(xì)說(shuō)一下。有興趣可以先看看文末的參考文章。
2. drawRect
繪制矩形方法,屬性與drawLine
大同小異,下面說(shuō)一些不同點(diǎn)。
fun drawRect( color: Color, topLeft: Offset = Offset.Zero, size: Size = this.size.offsetSize(topLeft), /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, style: DrawStyle = Fill, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
topLeft
是用來(lái)指定左上角的偏移量,如果沒(méi)有指定那么默認(rèn)從當(dāng)前畫(huà)布左上角開(kāi)始。size
用來(lái)指定矩形大小,如果沒(méi)有指定那么默認(rèn)就是當(dāng)前畫(huà)布的大小。style
是指實(shí)心還是空心。默認(rèn)Fill
實(shí)心,Stroke
空心。
3. drawRoundRect
繪制圓角矩形基本與矩形一致,只是多了一個(gè)設(shè)置圓角大小的參數(shù)drawRoundRect
,這里就不多說(shuō)明了。
4. drawImage
繪制圖片方法
fun drawImage( image: ImageBitmap, srcOffset: IntOffset = IntOffset.Zero, srcSize: IntSize = IntSize(image.width, image.height), dstOffset: IntOffset = IntOffset.Zero, dstSize: IntSize = srcSize, /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, style: DrawStyle = Fill, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
image
:需要繪制的圖片,具體可以使用ImageBitmap.imageResource(id = R.drawable.xxx)
方法獲取。srcOffset
:需要繪制圖片的左上角偏移量,默認(rèn)為圖像的原點(diǎn)。srcSize
: 圖片相對(duì)于srcOffset
的尺寸,默認(rèn)為圖像的寬高。dstOffset
: 繪制圖片的相對(duì)左上角的偏移量,這默認(rèn)為圖像的原點(diǎn)。dstSize
:繪制圖片的大小,默認(rèn)為srcSize
。
下面的代碼是繪制一張圖片的右下角區(qū)域,相對(duì)畫(huà)布偏移50 * 50,繪制的大小是200 * 200。
val imageBitmap = ImageBitmap.imageResource(id = R.mipmap.ic_launcher) Canvas(modifier = Modifier.fillMaxSize()) { drawImage( image = imageBitmap, srcOffset = IntOffset(imageBitmap.width / 2,imageBitmap.height / 2), srcSize = IntSize(imageBitmap.width, imageBitmap.height), dstOffset = IntOffset(50,50), dstSize = IntSize(200,200) ) }
效果如下:
5. drawCircle
繪制圓形方法
fun drawCircle( color: Color, radius: Float = size.minDimension / 2.0f, center: Offset = this.center, /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, style: DrawStyle = Fill, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
radius
:圓的半徑大小。center
:圓心位置。
6. drawArc
drawArc
可以用來(lái)繪制弧形或是扇形
fun drawArc( color: Color, startAngle: Float, sweepAngle: Float, useCenter: Boolean, topLeft: Offset = Offset.Zero, size: Size = this.size.offsetSize(topLeft), /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, style: DrawStyle = Fill, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
startAngle
: 開(kāi)始角度sweepAngle
: 弧線掃過(guò)的角度useCenter
: 弧線是否過(guò)圓心
這里就不舉例說(shuō)明了,可以用style
、useCenter
屬性自行組合嘗試。
7. drawPath
繪制路徑方法
fun drawPath( path: Path, color: Color, /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, style: DrawStyle = Fill, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
其實(shí)和Android中的path使用一樣,圍繞著moveTo、lineTo、close這些方法,也就不詳細(xì)說(shuō)明了。
8. drawPoints
繪制點(diǎn)的方法
fun drawPoints( points: List<Offset>, pointMode: PointMode, color: Color, strokeWidth: Float = Stroke.HairlineWidth, cap: StrokeCap = StrokeCap.Butt, pathEffect: PathEffect? = null, /*@FloatRange(from = 0.0, to = 1.0)*/ alpha: Float = 1.0f, colorFilter: ColorFilter? = null, blendMode: BlendMode = DefaultBlendMode )
points
:點(diǎn)的偏移位置pointMode
:點(diǎn)的繪制模式,PointMode.Points
分別畫(huà)出每個(gè)點(diǎn)。PointMode.Lines
每?jī)蓚€(gè)點(diǎn)畫(huà)成一條線段。 如果點(diǎn)數(shù)是奇數(shù),則忽略最后一個(gè)點(diǎn)。PointMode.Polygon
連接所有的點(diǎn)。
最后還有一個(gè)繪制橢圓方法drawOval
,用法大同小異,就不說(shuō)明了。
3. DrawScope拓展方法
1. inset
同時(shí)從左到上轉(zhuǎn)換DrawScope
坐標(biāo)空間,并修改當(dāng)前繪制區(qū)域的尺寸。
inline fun DrawScope.inset( left: Float, top: Float, right: Float, bottom: Float, block: DrawScope.() -> Unit ) {...}
inset
有點(diǎn)像是在原有的畫(huà)布上,嵌入了一個(gè)"新"的畫(huà)布,設(shè)置的left,top就是相應(yīng)的padding。
Canvas(modifier = Modifier.fillMaxSize()){ drawRect( color = Color.Blue, ) inset(100f, 100f, 100f, 100f) { drawRect( color = Color.Red, ) } }
2. translate
平移繪制區(qū)域
inline fun DrawScope.translate( left: Float = 0.0f, top: Float = 0.0f, block: DrawScope.() -> Unit ) {...}
只需要設(shè)置left、top方向移動(dòng)的距離即可。
3. rotate與rotateRad
旋轉(zhuǎn)繪制區(qū)域
inline fun DrawScope.rotate( degrees: Float, pivot: Offset = center, block: DrawScope.() -> Unit ) {...} inline fun DrawScope.rotateRad( radians: Float, pivot: Offset = center, block: DrawScope.() -> Unit ) {...}
degrees
是旋轉(zhuǎn)了多少角度。radians
是旋轉(zhuǎn)了多少弧度。pivot
是旋轉(zhuǎn)的中心點(diǎn),默認(rèn)是中心。
4. scale
縮放繪制區(qū)域。
inline fun DrawScope.scale( scaleX: Float, scaleY: Float, pivot: Offset = center, block: DrawScope.() -> Unit ) {...}
指定x、y方向上的縮放倍數(shù)即可。
5. clipRect
裁剪給定的矩形區(qū)域
inline fun DrawScope.clipRect( left: Float = 0.0f, top: Float = 0.0f, right: Float = size.width, bottom: Float = size.height, clipOp: ClipOp = ClipOp.Intersect, block: DrawScope.() -> Unit ) {...}
clipOp
:ClipOp.Intersect
是裁剪矩形的里面,ClipOp.Difference
是裁剪矩形的外面。
看個(gè)簡(jiǎn)單的例子,便于你的理解:
Canvas(modifier = Modifier.fillMaxSize()){ drawRect( color = Color.Blue, ) clipRect(200f, 200f, clipOp = ClipOp.Intersect) { drawRect( color = Color.Yellow, ) } }
左邊是ClipOp.Intersect
,右邊是ClipOp.Difference
clipPath
同理。
6. drawIntoCanvas
可以直接調(diào)用底層Canvas繪制的方法。我們用它實(shí)現(xiàn)一開(kāi)始的drawLine例子,畫(huà)一條對(duì)角線:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawIntoCanvas { val paint = Paint() paint.color = Color.Blue paint.strokeWidth = 1f it.drawLine( p1 = Offset(canvasWidth,0f), p2 = Offset(0f,canvasHeight), paint = paint ) } }
其中drawLine
方法,并不是一開(kāi)始DrawScope
中的drawLine
:
actual typealias NativeCanvas = android.graphics.Canvas private val EmptyCanvas = android.graphics.Canvas() @PublishedApi internal class AndroidCanvas() : Canvas { @PublishedApi internal var internalCanvas: NativeCanvas = EmptyCanvas override fun drawLine(p1: Offset, p2: Offset, paint: Paint) { internalCanvas.drawLine( p1.x, p1.y, p2.x, p2.y, paint.asFrameworkPaint() ) } }
可以看到最終調(diào)用了Android的Canvas api。
7. withTransform
執(zhí)行1個(gè)或多個(gè)轉(zhuǎn)換。也就是上面平移旋轉(zhuǎn)這些可以一塊執(zhí)行。
inline fun DrawScope.withTransform( transformBlock: DrawTransform.() -> Unit, drawBlock: DrawScope.() -> Unit ) {...}
4.參考
到此這篇關(guān)于Jetpack Compose Canvas繪制超詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Jetpack Compose Canvas內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何在Flutter中用小部件創(chuàng)建響應(yīng)式布局
由于Flutter的跨平臺(tái)、單一代碼庫(kù)的能力,了解屏幕管理以防止像柔性溢出錯(cuò)誤或糟糕的用戶界面設(shè)計(jì)這樣的問(wèn)題是至關(guān)重要的。本文將探討如何用靈活和擴(kuò)展的小部件創(chuàng)建響應(yīng)式布局,需要的可以參考一下2022-02-02Kotlin HttpURLConnection與服務(wù)器交互實(shí)現(xiàn)方法詳解
簡(jiǎn)單來(lái)說(shuō),HttpURLConnection 是發(fā)起HTTP請(qǐng)求的基礎(chǔ)類(lèi)庫(kù),提供了HTTP請(qǐng)求的基本功能,不過(guò)封裝的比較少,在使用時(shí)很多內(nèi)容都需要自己設(shè)置,也需要自己處理請(qǐng)求流和響應(yīng)流2022-09-09Android studio實(shí)現(xiàn)刮刮樂(lè)的方法
這篇文章主要為大家詳細(xì)介紹了Android studio實(shí)現(xiàn)刮刮樂(lè)的兩種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android獲取監(jiān)聽(tīng)SD卡狀態(tài)
本篇文章主要介紹了Android獲取監(jiān)聽(tīng)SD卡狀態(tài),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03android中寫(xiě)一個(gè)內(nèi)部類(lèi)來(lái)選擇文件夾中指定的圖片類(lèi)型實(shí)例說(shuō)明
選擇文件夾中指定的圖片類(lèi)型,本類(lèi)是用來(lái)選擇文件夾中是.jpg類(lèi)型的圖片具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下哈2013-06-06Android Studio 中aidl的自定義類(lèi)的使用詳解
這篇文章主要介紹了Android Studio 中aidl的自定義類(lèi)的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Android DaggerActivityComponent錯(cuò)誤解決辦法詳解
這篇文章主要介紹了Android DaggerActivityComponent錯(cuò)誤解決的相關(guān)資料,需要的朋友可以參考下2017-05-05