Идея, которую я ищу, заключается в следующем:
- Имейте цвет фона (в данном случае просто делайте градиент цветов)
- Черный передний план, закрывающий фон
- Нарисуйте путь на экране, который в некотором смысле сотрет черный передний план там, где он нарисован чтобы раскрыть фон.
Ниже мой код:
Код: Выделить всё
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//enableEdgeToEdge()
setContent {
SampleScratchPadTheme {
var reset by remember {
mutableStateOf(false)
}
Scaffold(modifier = Modifier.fillMaxSize(), floatingActionButton = {
FloatingActionButton(onClick = {
reset = true
}, shape = RoundedCornerShape(25.dp)) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Restart"
)
}
}) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
Column {
Sample(reset, resetCanvas = {
reset = false
})
}
}
}
}
}
}
@Composable
private fun Sample(
reset : Boolean,
resetCanvas : () -> Unit
) {
var circles = remember {
mutableStateListOf(Offset(-100f, -100f)) // start off screen
}
var erasedPoints by remember {
mutableStateOf(Path())
}
fun changeColor(): List {
return listOf(
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
),
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
),
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
)
)
}
var gradientColors by remember {
mutableStateOf(changeColor())
}
var pointerOffset by remember {
mutableStateOf(Offset(0f, 0f))
}
if(reset){
circles.clear()
erasedPoints.reset()
gradientColors = changeColor()
resetCanvas()
}
Box(modifier = Modifier
.fillMaxSize()
.clipToBounds()
.pointerInput("dragging") {
detectDragGestures(onDragStart = {
pointerOffset = it
erasedPoints.moveTo(pointerOffset.x, pointerOffset.y)
circles.add(pointerOffset)
}) { change, dragAmount ->
pointerOffset += dragAmount
erasedPoints.lineTo(pointerOffset.x, pointerOffset.y)
circles.add(pointerOffset)
}
}
.drawBehind {
drawRect(
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
)
)
}
.drawWithContent {
drawRect(Color.Black)
circles.forEach {
drawCircle(
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
), center = it,
radius = 25f,
blendMode = BlendMode.SrcIn
)
}
if (!erasedPoints.isEmpty) {
drawPath(
path = erasedPoints,
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
),
style = Stroke(
width = 50f,
cap = StrokeCap.Round,
join = StrokeJoin.Round
),
blendMode = BlendMode.SrcIn
)
}
}) {
}
}
Код: Выделить всё
drawRect(Color.Black)
circles.forEach {
drawCircle(
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
), center = it,
radius = 25f,
blendMode = BlendMode.SrcIn
)
}
if (!erasedPoints.isEmpty) {
drawPath(
path = erasedPoints,
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
),
style = Stroke(
width = 50f,
cap = StrokeCap.Round,
join = StrokeJoin.Round
),
blendMode = BlendMode.SrcIn
)
}

Изображение показывает желаемые результаты, но работает только тогда, когда я добавляю drawPath и прохожу через методы drawCircle.
Если я оставлю только drawPath и удалю цикл drawCircle, я думаю, это все, что нужно, то ничего не происходит экран. Просто черный.
Если я изменю режим наложения на BlendMode.CLEAR в drawCircle, я получу следующее:

Кажется, нет необходимости использовать оба метода. Думаю, все, что мне нужно, это drawPath.
Буду очень признателен за любую информацию или рекомендации.
************* ОТВЕТ **************
Благодаря Thracian я решил обновить свой код на случай, если кому-то еще понадобится ссылка. Я не последовал его примеру, а просто внес коррективы в две проблемы, на которые он указал. Это означает минимальное редактирование только для проверки концепции.
Код: Выделить всё
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//enableEdgeToEdge()
setContent {
SampleScratchPadTheme {
var reset by remember {
mutableStateOf(false)
}
Scaffold(modifier = Modifier.fillMaxSize(), floatingActionButton = {
FloatingActionButton(onClick = {
reset = true
}, shape = RoundedCornerShape(25.dp)) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Restart"
)
}
}) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
Column {
Sample(reset, resetCanvas = {
reset = false
})
}
}
}
}
}
}
@Composable
private fun Sample(
reset : Boolean,
resetCanvas : () -> Unit
) {
var circles = remember {
mutableStateListOf(Offset(-100f, -100f)) // start off screen
}
var erasedPoints by remember {
mutableStateOf(Path())
}
fun changeColor(): List {
return listOf(
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
),
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
),
Color(
Random.nextInt(255),
Random.nextInt(255),
Random.nextInt(255),
255
)
)
}
var gradientColors by remember {
mutableStateOf(changeColor())
}
var pointerOffset by remember {
mutableStateOf(Offset(0f, 0f))
}
if(reset){
circles.clear()
erasedPoints.reset()
gradientColors = changeColor()
pointerOffset = Offset.Unspecified
resetCanvas()
}
Box(modifier = Modifier
.fillMaxSize()
.clipToBounds()
.pointerInput("dragging") {
detectDragGestures(onDragStart = {
pointerOffset = it
erasedPoints.moveTo(pointerOffset.x, pointerOffset.y)
circles.add(pointerOffset)
}) { change, dragAmount ->
pointerOffset += dragAmount
erasedPoints.lineTo(pointerOffset.x, pointerOffset.y)
circles.add(pointerOffset)
}
}
.drawBehind {
drawRect(
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
)
)
}
.graphicsLayer {
compositingStrategy = CompositingStrategy.Offscreen
}
.drawWithContent {
drawRect(Color.Black)
/*circles.forEach {
drawCircle(
brush = Brush.linearGradient(
colors = gradientColors,
start = Offset.Zero,
end = Offset.Infinite
), center = it,
radius = 25f,
blendMode = BlendMode.SrcIn
)
}*/
if(pointerOffset != Offset.Unspecified){
if (!erasedPoints.isEmpty) {
drawPath(
path = erasedPoints,
color = Color.Transparent,
style = Stroke(
width = 50f,
cap = StrokeCap.Round,
join = StrokeJoin.Round
),
blendMode = BlendMode.Clear
)
}
}
}) {
}
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... foreground