Modifier.graphicsLayerでPCの開閉を再現してみた

Android Jetpack composeのModifier.graphicsLayerの紹介

https://developer.android.com/jetpack/compose/graphics/draw/modifiers?hl=ja


graphicsLayerを使うと，物体の位置や，回転，縮小などを指定することができます．

### 指定可能な主な引数

```kotlin
graphicsLayer(
    scaleX: Float,
    scaleY: Float,
    alpha: Float,
    translationX: Float,
    translationY: Float,
    shadowElevation: Float,
    rotationX: Float,
    rotationY: Float,
    rotationZ: Float,
    cameraDistance: Float,
    transformOrigin: TransformOrigin,
)
```

各引数を簡単に説明します．
具体例はこのサイトで物凄く分かりやすくまとめられてます．

https://medium.com/mobile-app-development-publication/have-fun-with-jetpack-compose-graphicslayer-modifier-e39c12a4791f

### scaleX/Y
X軸Y軸で大きさを変化

```kotlin
Text("a", modifier=Modifier.graphicsLayer(scaleX=1.5f))

```

### alpha
透明度の変化

### translationX/Y
X軸Y軸方向の横移動

### shadowElevation
影の距離

### rotationX/Y/Z
X軸Y軸Z軸に対して回転
回転の基準点は，transformOriginで指定

### cameraDistance
回転時にどれだけ遠近感をつけるか．小さいほどこちらに向かって大きく拡大する


## 実装例
回転角によって表示する画像を切り替えることで，下記のようなコトが出来ます．
（rotationXが90以上の場合で切り替えています．)

![trimmed.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691046/1d92bd76-f92e-c631-476e-e58668718821.gif)

```kotlin
@Composable
fun PC(
    rotateX: Float,
    width: Dp,
    height: Dp,
    cameraDistance: Float,
){
    val isOpen = (abs(rotateX) % 360) > 90f
    Box {
        Box(
            modifier = Modifier
                .width(width)
                .height(height)
                .clip(RoundedCornerShape(8))
        ){
            Image(painterResource(R.drawable.keyboard),
                "キーボード画像",
                contentScale = ContentScale.FillBounds,)
        }
        if(isOpen){
            Box(
                modifier = Modifier
                    .graphicsLayer(
                        rotationX = rotateX,
                        transformOrigin = TransformOrigin(0.5f, 0f),
                        cameraDistance = cameraDistance
                    )
                    .width(width)
                    .height(height)
                    .clip(RoundedCornerShape(8))
            ){
                Image(painterResource(R.drawable.screen),
                    "スクリーン画像",
                    contentScale = ContentScale.FillBounds,)
            }
        }else{
            Box(
                modifier = Modifier
                    .graphicsLayer(
                        rotationX = rotateX,
                        transformOrigin = TransformOrigin(0.5f, 0f),
                        cameraDistance = cameraDistance
                    )
                    .width(width)
                    .height(height)
                    .clip(RoundedCornerShape(8))
            ){
                Image(painterResource(R.drawable.top),
                    "PC上面画像",
                    contentScale = ContentScale.FillBounds,)
            }
        }
    }
}
```

```kotlin
@Composable
fun PcOpenAndClose(){
    var open by remember{ mutableStateOf(false) }
    val alpha: Float by animateFloatAsState(
        if (open) 0f else 130f,
        animationSpec = tween(
            durationMillis = 800,
            delayMillis = 50,
            easing = LinearOutSlowInEasing
        ), label = ""
    )

    Column(
        horizontalAlignment = Alignment.CenterHorizontally
    ){
        PC(rotateX = alpha, width = 230.dp, height = 130.dp, cameraDistance = 11.0f)
        Spacer(Modifier.height(20.dp))
        Button(onClick = { open = !open }) {
            Text(text = "ぽちぽち")
        }
    }
}
```