改变Composable的布局方向

37

我想将特定组件的方向设置为从右到左(RTL)


@Composable
fun ViewToBeChanged() {
  Row {
     Image()
     Column {
        Text("Title")
        Text("Subtitle")
    }
  }
}

可能吗?

Jetpack compose的布局文档中提到了LocalLayoutDirection

通过更改LocalLayoutDirection compositionLocal来更改组合的布局方向。

但是我不知道如何在组合中使用它才能生效。


如果您不想切换到RTL布局,而只是想以不同的方式绘制布局,比如从上到下(像Column)或从开始到结束(像Row),那么ConstraintLayout的灵活性可能正是您所需要的。这里有一个Compose实现:https://developer.android.com/jetpack/androidx/releases/constraintlayout - Peter F
5个回答

62
你可以使用 CompositionLocalProvider 来提供自定义的 LocalLayoutDirection。像这样:
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl ) {
    Column(Modifier.fillMaxWidth()) {
        Text("Title")
        Text("Subtitle")
    }
}

17

由于我没有你的图片,我对你的组件进行了调整:

@Composable
fun ViewToBeChanged() {
  Row {
    Text("Foo", modifier = Modifier.padding(end = 8.dp))

    Column {
      Text("Title")
      Text("Subtitle")
    }
  }
}

那给我们带来了:

ViewToBeChanged()渲染

切换到RTL的一种方法是使用 CompositionLocalProviderLocalLayoutDirection

@Composable
fun RtlView() {
  CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
    Row {
      Text("Foo", modifier = Modifier.padding(end = 8.dp))

      Column {
        Text("Title")
        Text("Subtitle")
      }
    }
  }
}

在这里,我们说我们正在覆盖CompositionLocal的布局方向,用于提供给CompositionLocalProvider()的尾随lambda的内容。这给了我们:

RtlView() rendering

这将更改可组合树的此分支所使用的布局方向,对于可组合本身。英语仍然是从左到右的语言,因此文本不受影响。


5
作为对其他答案的概括,如果需要在不同的组合中使用,我们可以定义如下内容。
@Composable
fun RightToLeftLayout(content: @Composable () -> Unit) {
    CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
        content()
    }
}

然后只需要使用

RightToLeftLayout {
    ViewToBeChanged()
}

或者

RightToLeftLayout {
    Row {
        ...
    }
}
   

4
对于特定的Row,您可以使用horizontalArrangement参数来影响RTL / LTR行为。默认值是Arrangement.Start,它考虑布局方向。使用其中之一{{link1:Arrangement.Absolute}}允许您提供忽略布局方向的排列。
在您的示例中:
@Composable
fun ViewToBeChanged() {
  Row(horizontalArrangement = Arrangement.Right) {
     Image()
     Column {
        Text("Title")
        Text("Subtitle")
    }
  }
}

这应该是正确的答案。如其他评论中所提到的,使用CompositionLocalProvider存在修改子树中所有元素的风险。 - Christopher Perry

4
使用CompositionLocalProvider更改方向有可能导致所有子布局更改方向的潜在风险,这可能不是我们想要的。而使用LazyColumn或LazyRow可以反转布局,但子布局的功能将受到限制,并且存在一些奇怪的限制,因此这是我的解决方案。
@Composable
fun ReversibleRow(
    modifier: Modifier = Modifier,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    verticalAlignment: Alignment.Vertical = Alignment.Top,
    reverseLayout: Boolean = false,
    content: @Composable RowScope.() -> Unit
) {
    val originDirection = LocalLayoutDirection.current
    val direction = when {
        reverseLayout -> when (originDirection) {
            LayoutDirection.Rtl -> LayoutDirection.Ltr
            else -> LayoutDirection.Rtl
        }
        else -> originDirection
    }
    CompositionLocalProvider(LocalLayoutDirection provides direction) {
        Row(modifier, horizontalArrangement, verticalAlignment) {
            CompositionLocalProvider(LocalLayoutDirection provides originDirection) {
                content()
            }
        }
    }
}

使用ReversibleRow替换Row,同样适用于Column。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接