android compose drawWithContent 使用

android compose drawWithContent 使用

所有绘制命令均在 Compose 中使用绘制修饰符完成。Compose 中有三个主要的绘制修饰符:

基本绘制修饰符为 drawWithContent,您可以在其中确定可组合项的绘制顺序以及从修饰符内发出的绘制命令。drawBehind 是围绕 drawWithContent 的便利封装容器,其绘制顺序设为可组合项内容的后方。drawWithCache 会在其内部调用 onDrawBehindonDrawWithContent,并提供一种机制来缓存在其中创建的对象。

复制代码
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.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.wn.androidcomposedemo1.R
import com.wn.androidcomposedemo1.ui.theme.AndroidComposeDemo1Theme

/**
 * Author : wn
 * Email : maoning20080808@163.com
 * Date : 2026/7/3 17:29
 * Description :
 * 所有绘制命令均在 Compose 中使用绘制修饰符完成。Compose 中有三个主要的绘制修饰符:
 * drawWithContent
 * drawBehind
 * drawWithCache
 */
class DrawContentActivity : ComponentActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AndroidComposeDemo1Theme() {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    DrawBehindDemo()
                }
            }
        }
    }

    @Composable
    fun DrawBehindDemo(){
        Column(horizontalAlignment = Alignment.CenterHorizontally) {
            Spacer(Modifier.height(20.dp))
            Text("使用Modifier.drawBehind、drawWithCache", fontSize = 20.sp, color = Color.Red)
            Spacer(Modifier.height(20.dp))
            DrawBehindExample()
            Spacer(Modifier.height(20.dp))
            DrawWithCacheExample()
            Spacer(Modifier.height(20.dp))
            BlendModeExample()
            Spacer(Modifier.height(20.dp))
            BlendModeExample2()
        }
    }

    @Composable
    fun DrawBehindExample(){
        Text("Hello Compose!", fontSize = 30.sp,
            modifier = Modifier.drawBehind{
                drawRoundRect(Color(0xFFBBAAEE),
                    cornerRadius = CornerRadius(10.dp.toPx())
                )
            }.padding(12.dp)
        )
    }

    @Composable
    fun DrawWithCacheExample(){
        Text("Hello Compose!", fontSize = 30.sp,
            modifier = Modifier
                .drawWithCache{
                    val brush = Brush.linearGradient(
                        listOf(
                            Color(0xFF9E82F0),
                            Color(0xFF42A5F5)
                        )
                    )
                    onDrawBehind {
                        drawRoundRect(
                            brush,
                            cornerRadius = CornerRadius(10.dp.toPx())
                        )
                    }
                }
                .padding(12.dp)
        )
    }

    @Composable
    fun BlendModeExample(){
        Image(
            painter = painterResource(id = R.drawable.dog),
            contentDescription = stringResource(R.string.image_description),
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .size(200.dp)
                .aspectRatio(1f)
                .background(
                    Brush.linearGradient(
                        listOf(
                            Color(0xFFC5E1A5),
                            Color(0xFF80DEEA)
                        )
                    )
                )
                .padding(18.dp)
                .graphicsLayer{
                    compositingStrategy = CompositingStrategy.Offscreen
                }
                .drawWithCache{
                    val path = Path()
                    path.addOval(
                        Rect(
                            topLeft = Offset.Zero,
                            bottomRight = Offset(size.width, size.height)
                            )
                    )
                    onDrawWithContent {
                        clipPath(path){
                            this@onDrawWithContent.drawContent()
                        }

                        val dotSize = size.width / 8f

                        drawCircle(
                            Color.Black,
                            radius = dotSize,
                            center = Offset(
                                x = size.width - dotSize,
                                y = size.height - dotSize
                            ),
                            blendMode = BlendMode.Clear
                        )

                        drawCircle(
                            Color(0xFFEF5350), radius = dotSize * 0.8f,
                            center = Offset(
                                x = size.width - dotSize,
                                y = size.height - dotSize
                            )
                        )
                    }
                }
        )
    }

    //不使用CompositingStrategy.Offscreen
    @Composable
    fun BlendModeExample2(){
        Image(
            painter = painterResource(id = R.drawable.dog),
            contentDescription = stringResource(R.string.image_description),
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .size(200.dp)
                .aspectRatio(1f)
                .background(
                    Brush.linearGradient(
                        listOf(
                            Color(0xFFC5E1A5),
                            Color(0xFF80DEEA)
                        )
                    )
                )
                .padding(18.dp)
                .graphicsLayer{
                    //compositingStrategy = CompositingStrategy.Offscreen
                }
                .drawWithCache{
                    val path = Path()
                    path.addOval(
                        Rect(
                            topLeft = Offset.Zero,
                            bottomRight = Offset(size.width, size.height)
                        )
                    )
                    onDrawWithContent {
                        clipPath(path){
                            this@onDrawWithContent.drawContent()
                        }

                        val dotSize = size.width / 8f

                        drawCircle(
                            Color.Black,
                            radius = dotSize,
                            center = Offset(
                                x = size.width - dotSize,
                                y = size.height - dotSize
                            ),
                            blendMode = BlendMode.Clear
                        )

                        drawCircle(
                            Color(0xFFEF5350), radius = dotSize * 0.8f,
                            center = Offset(
                                x = size.width - dotSize,
                                y = size.height - dotSize
                            )
                        )
                    }
                }
        )
    }
}