android compose 自定义Painter绘制图形 使用
在 Compose 中,Painter 对象用于表示可以绘制的内容(替代 Android 中定义的 Drawable API),并且会影响使用该对象的相应可组合项的测量和布局。BitmapPainter 采用 ImageBitmap,后者可以在屏幕上绘制 Bitmap。
对于大多数用例,使用 painterResource() 函数会为该资源返回正确的 Painter(例如 BitmapPainter 或 VectorPainter)。如需详细了解两者之间的差异,请参阅 ImageBitmap 与 ImageVector 部分。
Painter 与 DrawModifier 不同,后者在绘制时严格遵守为其指定的边界,并且不会影响可组合项的测量或布局。
如需创建自定义 Painter,请扩展 Painter 类并实现 onDraw 方法,从而允许访问 DrawScope 以绘制自定义图形。您还可以替换 intrinsicSize,它将用于影响其所属的可组合项:
官方网站:自定义 Painter | Jetpack Compose | Android Developers

package com.wn.androidcomposedemo1.basegoogleimage
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.toSize
import com.wn.androidcomposedemo1.R
import com.wn.androidcomposedemo1.ui.theme.AndroidComposeDemo1Theme
import kotlin.math.roundToInt
/**
* Author : wn
* Email : maoning20080808@163.com
* Date : 2026/7/3 11:35
* Description : 自定义Painter绘制图形
*/
class ImagePainterActivity : ComponentActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AndroidComposeDemo1Theme() {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
ImagePainterExample()
//CustomPainterUsage() 官方的demo,也显示不正常。
}
}
}
}
@Composable
fun ImagePainterExample(){
val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
val customPainter = remember {
OverlayImagePainter2(rainbowImage,dogImage)
}
Image(
painter = customPainter,
contentDescription = stringResource(R.string.image_description),
contentScale = ContentScale.Crop,
modifier = Modifier.wrapContentSize()
)
}
}
class OverlayImagePainter2 constructor(
private val image : ImageBitmap,
private val imageOverlay : ImageBitmap,
private val srcOffset : IntOffset = IntOffset.Zero,
private val srcSize : IntSize = IntSize(image.width, image.height),
private val overlaySize : IntSize = IntSize(imageOverlay.width, imageOverlay.height)
) : Painter(){
private val size : IntSize = validateSize(srcOffset, srcSize)
override fun DrawScope.onDraw() {
//绘制底图
drawImage(
image,
srcOffset,
srcSize,
dstSize = IntSize(
this@onDraw.size.width.roundToInt(),
this@onDraw.size.height.roundToInt()
)
)
//绘制叠加图
drawImage(
imageOverlay,
srcOffset,
overlaySize,
dstSize = IntSize(
this@onDraw.size.width.roundToInt(),
this@onDraw.size.height.roundToInt()
),
blendMode = BlendMode.SrcIn
)
}
override val intrinsicSize: Size
get() = size.toSize()
private fun validateSize(srcOffset : IntOffset, srcSize : IntSize) : IntSize{
require(
srcOffset.x >= 0 &&
srcOffset.y >= 0 &&
srcSize.width >= 0 &&
srcSize.height >= 0 &&
srcSize.width <= image.width &&
srcSize.height <= image.height
)
return srcSize
}
}