やはり Java のライブラリ群を使えることは素晴らしいことです。
以下、サンプルコードを参考に Activity を書き換えます。
👉 KlassenKonstantin/ComposePhysicsLayout: A custom Compose layout backed by a physics engine
class MainActivity : ComponentActivity() {
@SuppressLint("SourceLockedOrientationActivity")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContent {
PhysicsLayoutTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
val simulation = rememberSimulation()
val balls = remember { mutableStateListOf<BallMeta>() }
GravitySensor {
simulation.setGravity(it.copy(x = -it.x).times(3f))
}
LaunchedEffect(Unit) {
var i = 0
val count = colors.count()
while (true) {
balls.add(BallMeta(color = colors[i % count]))
delay(100)
i++
}
}
LaunchedEffect(Unit) {
delay(5000)
while (true) {
balls.removeFirst()
delay(100)
}
}
Box {
PhysicsLayout(
modifier = Modifier.systemBarsPadding(),
simulation = simulation
) {
Block( 0, -200)
Block(-125, -100)
Block( 125, -100)
Block( 0, 0)
Block(-100, 100)
Block( 100, 100)
Block( 0, 200)
balls.forEach { meta ->
Ball(0, -350, meta = meta)
}
}
}
}
}
}
}
}
@Composable
fun PhysicsLayoutScope.Block(x: Int, y: Int) {
val offset = offsetDp(x, y)
Card(
modifier = Modifier
.body(
isStatic = true,
initialTranslation = offset
)
) {
Spacer(
modifier = Modifier
.size(62.dp)
.background(color = Color.Gray)
)
}
}
@Composable
fun PhysicsLayoutScope.Ball(x: Int, y: Int, meta: BallMeta) {
val initialOffset = offsetDp(x, y)
Card(
modifier = Modifier.body(
id = meta.id,
shape = RoundedCornerShape(meta.corner),
initialTranslation = Offset(initialOffset.x, initialOffset.y),
initialImpulse = Offset((Random.nextFloat() - 0.5f) * 2, (Random.nextFloat()) * 2),
),
shape = RoundedCornerShape(meta.corner),
colors = CardDefaults.cardColors(containerColor = meta.color)
) {
Icon(
modifier = Modifier
.size(32.dp)
.padding(4.dp),
imageVector = Icons.Rounded.Rocket,
contentDescription = null,
tint = Color.White
)
}
}
@Composable
fun offsetDp(x: Int, y: Int) = with(LocalDensity.current) { Offset(x.dp.toPx(), y.dp.toPx()) }
@Immutable
data class BallMeta(
val id: String = System.currentTimeMillis().toString(),
val color: Color,
val corner: Int = listOf(0, 50).shuffled()[0]
)
private val colors = listOf(
Color(0xFFEF5350), Color(0xFFEC407A), Color(0xFFAB47BC), Color(0xFF7E57C2),
Color(0xFF29B6FC), Color(0xFF26C6DA), Color(0xFF26A69A), Color(0xFF66BB6A),
Color(0xFF9CCC65), Color(0xFFD4E157), Color(0xFFFFEE58), Color(0xFFFFCA28),
Color(0xFFFFA726), Color(0xFFFF7043), Color(0xFF8D6E63), Color(0xFFBDBDBD),
Color(0xFF78909C)
)
強力です。
👉 dyn4j
👉 【Jetpack Compose】dp / px / sp の相互変換