✨ Эффект ЭЛТ-экрана в Jetpack Compose
ЭЛТ-мониторы — это размытые края, линии сканирования и лёгкое свечение. Такой эффект можно воспроизвести в Compose с помощью GraphicsLayer, градиентов и размытия.
🔹 Базовый принцип
Мы один раз записываем контент во внеэкранный буфер и многократно перерисовываем его разными слоями.
val graphicsLayer = rememberGraphicsLayer()
Box(Modifier.drawWithContent {
graphicsLayer.record { drawContent() }
}) {
content()
}
Теперь drawLayer(graphicsLayer) можно использовать в любых эффектах.
🔹 Линии сканирования
Создаём повторяющиеся градиенты — вертикальные и горизонтальные:
private fun DrawScope.drawScanLines(alpha: Float, blend: BlendMode) {
val c = Colors.Black.copy(alpha)
drawRect(
brush = Brush.verticalGradient(
0f to c, 0.4f to c, 0.4f to Colors.Transparent, 1f to Colors.Transparent,
tileMode = TileMode.Repeated, endY = 10f
),
blendMode = blend
)
}
Добавляем их поверх слоя:
.drawBehind {
layer {
drawLayer(graphicsLayer)
drawScanLines(alpha = 1f, blend = BlendMode.DstOut)
}
}DstOut вычитает градиент и создаёт характерный "CRT-срез".
🔹 Размытие и свечение
Для реалистичного свечения рисуем несколько слоёв с разным blur/scale/alpha:
val blurLayers = listOf(
Triple(5.dp, .3f, 1.02f to 1.03f),
Triple(0.dp, .8f, 1f to 1f),
Triple(10.dp, .6f, 1.001f to 1f),
)
Каждый слой:
Box(
Modifier
.matchParentSize()
.blur(blur, BlurredEdgeTreatment.Unbounded)
.graphicsLayer { scaleX = scale.first; scaleY = scale.second; this.alpha = alpha }
.drawBehind {
layer {
drawLayer(graphicsLayer)
drawScanLines(1f, BlendMode.DstOut)
}
}
)
🔹 Дрожание экрана
var shake by remember { mutableStateOf(Offset.Zero) }
LaunchedEffect(Unit) {
while (true) {
shake = Offset(
Random.nextFloat() * Random.nextInt(-1, 1),
Random.nextFloat() * Random.nextInt(-1, 1),
)
delay(32)
}
}
И применяем:
.graphicsLayer {
translationX = shake.x
translationY = shake.y
}🐸 Библиотека мобильного разработчика
#PixelPerfect #MiddlePath #Kotlin