如何旋转可组合项并使其填充其父对象?

例如,我有一个列,在屏幕上填充了两个盒子,占据了一半的大小.

Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Box(
                modifier = Modifier
                    .rotate(90f)
                    .fillMaxSize()
                    .weight(1f)
                    .background(Color.Red),
                contentAlignment = Alignment.Center
            ) {
                Text("1", fontSize = 100.sp)
            }
            Box(
                modifier = Modifier
                    .rotate(90f)
                    .fillMaxSize()
                    .weight(1f)
                    .background(Color.Blue),
                contentAlignment = Alignment.Center
            ) {
                Text("2", fontSize = 100.sp)
            }
}

enter image description here

色雷斯人 comments 后编辑:

这看起来更好,但我得到的最大高度似乎是错误的,我可以在布局判断器中看到带约束的盒子的大小是正确的

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        BoxWithConstraints(modifier = Modifier.fillMaxSize().weight(1f)) {
            Box(
                modifier = Modifier
                    .rotate(90f)
                    .width(maxHeight)
                    .height(maxWidth)
                    .background(Color.Red),
                contentAlignment = Alignment.Center
            ) {
                Text("1", fontSize = 100.sp)
            }
        }
        BoxWithConstraints(modifier = Modifier.fillMaxSize().weight(1f)) {
            Box(
                modifier = Modifier
                    .rotate(90f)
                    .width(maxHeight)
                    .height(maxWidth)
                    .background(Color.Blue),
                contentAlignment = Alignment.Center
            ) {
                Text("2", fontSize = 100.sp)
            }
        }

enter image description here

推荐答案

修改器.旋转是

@Stable
fun Modifier.rotate(degrees: Float) =
    if (degrees != 0f) graphicsLayer(rotationZ = degrees) else this

修改器.graphicsLayer{}不会更改可组合对象的尺寸和物理位置,也不会触发重新组合,这对于设置动画或更改视觉表示非常有用.

你们也可以在我的问题here中看到,即使我改变了比例和绿色矩形的位置,在父对象中的位置也并没有改变.

  • 使内容绘制到绘制层的[Modifier.Element].这个

但是,修改器之后的任何修改器.graphicsLayer基于新的比例、平移或旋转apply.最容易看到的是在graphicsLayer之前和之后绘制边框.

Column(modifier = Modifier.fillMaxSize()) {
    val context = LocalContext.current
    Row(modifier = Modifier.fillMaxSize()) {
        Box(
            modifier = Modifier
                .size(100.dp, 200.dp)
                .border(2.dp, Color.Red)
                .zIndex(1f)
                .clickable {
                    Toast
                        .makeText(context, "Before Layer", Toast.LENGTH_SHORT)
                        .show()
                }
                .graphicsLayer {
                    translationX = 300f
                    rotationZ = 90f
                }
                .border(2.dp, Color.Green)
                .clickable {
                    Toast
                        .makeText(context, "After Layer", Toast.LENGTH_SHORT)
                        .show()
                }
        )
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(200.dp)
                .background(Color.Yellow)
        )
    }
}

若你们勾选这个例子,你们会看到,即使我们旋转了黄色背景框左侧的可组合性,也并没有改变,因为我们并没有改变左侧可组合性的实际形式.

enter image description here

@Composable
private fun MyComposable() {
    Column(modifier = Modifier.fillMaxSize()) {

        Spacer(modifier = Modifier.height(300.dp))


            Column(modifier = Modifier.fillMaxSize()) {

                var angle by remember { mutableStateOf(0f) }

                LaunchedEffect(key1 = Unit) {
                    delay(2000)
                    angle = 90f
                }


                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .weight(1f)
                        .background(Color.Red)
                        .rotate(angle),
                    contentAlignment = Alignment.Center
                ) {
                    Text("1", fontSize = 100.sp)
                }

                Spacer(modifier =Modifier.height(8.dp))

                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .weight(1f)
                        .background(Color.Blue)
                        .rotate(angle),
                    contentAlignment = Alignment.Center
                ) {
                    Text("2", fontSize = 100.sp)
                }
            }
        }
}

enter image description here

增加垫片,使箱子的宽度和高度不均匀,以供演示.

正如我在示例中所发布的,gif旋转顺序决定了我们旋转的内容.

修饰符=修饰符

这设置了大小,它从不旋转父对象,而是旋转内容或子对象,因为我们在旋转之前设置了大小和背景.若子对象的宽度不大于父对象的高度,则该答案有效.

如果子对象具有修饰符.当我们旋转时,fillSize()或子对象的宽度大于父对象的高度,如下图所示.所以我们需要在旋转后将其zoom 回父对象,因为我们没有更改父对象的维度.

@Composable
private fun MyComposable2() {
    var angle by remember { mutableStateOf(0f) }

    LaunchedEffect(key1 = Unit) {
        delay(2000)
        angle = 90f
    }

    

    Column(modifier = Modifier.fillMaxSize()) {

        Spacer(modifier = Modifier.height(100.dp))

        BoxWithConstraints(
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp)
        ) {

            val width = maxWidth
            val height = maxHeight / 2

            val newWidth = if (angle == 0f) width else height
            val newHeight = if (angle == 0f) height else width


            Column(modifier = Modifier.fillMaxSize()) {

                Box(
                    modifier = Modifier
                        .border(3.dp, Color.Red)
                        .size(width, height)
                        .graphicsLayer {
                            rotationZ = angle
                            scaleX = newWidth/width
                            scaleY = newHeight/height
                        }
                        .border(5.dp, Color.Yellow),
                    contentAlignment = Alignment.Center
                ) {

                    Image(
                        modifier = Modifier
                            .border(4.dp, getRandomColor())
                            .fillMaxSize(),
                        painter = painterResource(id = R.drawable.landscape1),
                        contentDescription = "",
                        contentScale = ContentScale.FillBounds
                    )
                }

                Box(
                    modifier = Modifier
                        .border(3.dp, Color.Red)
                        .graphicsLayer {
                            rotationZ = angle
                            scaleX = newWidth/width
                            scaleY = newHeight/height
                        }
                        .size(width, height)
                        .border(5.dp, Color.Yellow),
                    contentAlignment = Alignment.Center
                ) {

                    Image(
                        modifier = Modifier
                            .border(4.dp, getRandomColor())
                            .fillMaxSize(),
                        painter = painterResource(id = R.drawable.landscape1),
                        contentDescription = "",
                        contentScale = ContentScale.FillBounds
                    )
                }

            }
        }
    }
}

在左边,我们不zoom ,只旋转

enter image description here enter image description here

Android相关问答推荐

错误:无法解析Symbol@style/Theme. Androidstudio in AndroidManifest.html for Kotlin Android Development''

即使安装了Chrome和YouTube,Android对action_view a YouTube URL的意图也是空的

Kotlin DSL:为什么我可以从Play Store获取发布版本的日志(log)?

NativeScript在`ns run android`上重复Kotlin类

Jetpack Compose:带芯片的Textfield

如何在同一行中滚动自定义布局和惰性列,就好像它们是一个组件一样

将输出写入已发布的 Android 应用程序中的日志(log)文件?

如何将DrawableId参数传递给XML布局?

如何仅使用您的 Android 应用程序定位平板电脑?

在 Material 3 TopAppBar 代码的哪个位置定义了填充?

浏览器未命中断点判断 USB 连接设备

视觉转换后获取文本

在 Jetpack Compose 中单击时更改表面项目的背景 colored颜色

记住或不记得derivedStateOf

在jetpack compose中将图像添加到脚手架顶部栏

为什么我不能在屏幕外拿任何物体

操作系统会终止已启动的服务并调用Service.onDestroy吗?

如何在 flow.stateIn() 之后从流中的另一个函数发出emits ?

现代Android中的后台处理

Android 模拟器没有响应 Xamarin 的 AMD 进程的问题