Last active
January 14, 2026 21:49
-
-
Save brkckr/83a0b77a23af187cd6587945c3e8f9c1 to your computer and use it in GitHub Desktop.
Bouncing DVD logo animation on Jetpack Compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @Composable | |
| fun DVDScreen() { | |
| var dvdVideoSize by remember { mutableStateOf(Size.Zero) } // dvd+video size | |
| var isSizeReady by remember { mutableStateOf(false) } // is size ready? | |
| var velocityX by remember { mutableFloatStateOf(5f) } | |
| var velocityY by remember { mutableFloatStateOf(5f) } | |
| var textColor by remember { mutableStateOf(Color.Blue) } | |
| fun randomColor(): Color { | |
| return Color( | |
| red = Random.nextFloat(), | |
| green = Random.nextFloat(), | |
| blue = Random.nextFloat(), | |
| alpha = 1f | |
| ) | |
| } | |
| val configuration = LocalConfiguration.current | |
| val screenWidth = with(LocalDensity.current) { configuration.screenWidthDp.dp.toPx() } | |
| val screenHeight = with(LocalDensity.current) { configuration.screenHeightDp.dp.toPx() } | |
| var positionX by remember { mutableFloatStateOf(0f) } | |
| var positionY by remember { mutableFloatStateOf(0f) } | |
| LaunchedEffect(Unit) { | |
| while (true) { | |
| if (isSizeReady) { | |
| positionX += velocityX // update x position | |
| positionY += velocityY // update y position | |
| var colorChanged = false // flag for collision | |
| // check for collision with left edge | |
| if (positionX <= 0f) { | |
| velocityX = -velocityX // reverse x velocity | |
| positionX = 0f // clamp position to left | |
| colorChanged = true // trigger color change | |
| } | |
| // check for collision with right edge | |
| else if (dvdVideoSize != Size.Zero && positionX + dvdVideoSize.width >= screenWidth) { | |
| velocityX = -velocityX | |
| positionX = screenWidth - dvdVideoSize.width | |
| colorChanged = true | |
| } | |
| // check for collision with top edge | |
| if (positionY <= 0f) { | |
| velocityY = -velocityY // reverse y velocity | |
| positionY = 0f | |
| colorChanged = true | |
| } | |
| // check for collision with bottom edge | |
| else if (dvdVideoSize != Size.Zero && positionY + dvdVideoSize.height >= screenHeight) { | |
| velocityY = -velocityY | |
| positionY = screenHeight - dvdVideoSize.height | |
| colorChanged = true | |
| } | |
| // change color if a collision occurred | |
| if (colorChanged) { | |
| textColor = randomColor() | |
| } | |
| delay(16) // wait for 60 fps | |
| } | |
| } | |
| } | |
| Box( | |
| modifier = Modifier | |
| .fillMaxSize() | |
| .background(Color.Black), | |
| contentAlignment = Alignment.TopStart | |
| ) { | |
| Column( | |
| modifier = Modifier | |
| .offset( | |
| x = with(LocalDensity.current) { positionX.toDp() }, | |
| y = with(LocalDensity.current) { positionY.toDp() } | |
| ) | |
| .onGloballyPositioned { layoutCoordinates -> | |
| val size = layoutCoordinates.size | |
| if (size.width > 0 && size.height > 0) { | |
| dvdVideoSize = Size(size.width.toFloat(), size.height.toFloat()) | |
| isSizeReady = true | |
| } | |
| }, | |
| horizontalAlignment = Alignment.CenterHorizontally, | |
| verticalArrangement = Arrangement.spacedBy(0.dp) | |
| ) { | |
| Text( | |
| text = "DVD", | |
| style = TextStyle( | |
| fontSize = 72.sp, | |
| fontStyle = FontStyle.Italic, | |
| fontWeight = FontWeight.Bold, | |
| color = textColor, | |
| letterSpacing = 0.sp | |
| ) | |
| ) | |
| Text( | |
| text = "VIDEO", | |
| color = Color.Black, | |
| fontSize = 24.sp, | |
| fontWeight = FontWeight.Medium, | |
| textAlign = TextAlign.Center, | |
| letterSpacing = 4.sp, | |
| modifier = Modifier | |
| .width(with(LocalDensity.current) { dvdVideoSize.width.toDp() }) | |
| .drawBehind { | |
| drawOval( | |
| color = textColor, | |
| size = Size(dvdVideoSize.width, size.height) | |
| ) | |
| } | |
| ) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
