android compose 自定义Painter绘制图形 使用

android compose 自定义Painter绘制图形 使用

在 Compose 中,Painter 对象用于表示可以绘制的内容(替代 Android 中定义的 Drawable API),并且会影响使用该对象的相应可组合项的测量和布局。BitmapPainter 采用 ImageBitmap,后者可以在屏幕上绘制 Bitmap

对于大多数用例,使用 painterResource() 函数会为该资源返回正确的 Painter(例如 BitmapPainterVectorPainter)。如需详细了解两者之间的差异,请参阅 ImageBitmap 与 ImageVector 部分。

PainterDrawModifier 不同,后者在绘制时严格遵守为其指定的边界,并且不会影响可组合项的测量或布局。

如需创建自定义 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
    }
}
相关推荐
wxson72821 小时前
【Android视频监控系统技术总结】
android·音视频
hunterandroid3 小时前
[Android 从零到一] LiveData 粘性事件与单次消费:从重复触发到可靠事件总线
android
hunterandroid3 小时前
[Android 从零到一] Android 事件分发机制:从 ACTION_DOWN 到 View 事件消费链路
android
阿巴斯甜3 小时前
adb‑shell 全套命令实操总结
android
奔跑的架构师4 小时前
[A-49]ARMv9/v8-PSCI接口规范与工作流程简介
android·linux·arm开发·arm
AFinalStone4 小时前
Android 7系统国际化(七)Resources 与 AssetManager 源码剖析
android·国际化·local
Android-Flutter5 小时前
Android 内存泄漏详解
android·kotlin
catchadmin5 小时前
Fiber 与 PHP 8.6 Polling API 异步初探
android·开发语言·php
Android-Flutter6 小时前
android Handler , Looper , Message , MessageQueue 详解
android·kotlin