Jetpack撰写-滚动到集中的可组合在列



我的UI是这样的:

val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxSize(1F)
.padding(horizontal = 16.dp)
.verticalScroll(scrollState)
) {
TextField(...)
// multiple textfields
TextField(
//...
modifier = Modifier.focusOrder(countryFocus).onFocusChanged {
if(it == FocusState.Active) {
// scroll to this textfield
}
},
)
}

我在这个列中有多个TextFields,当其中一个集中时,我想滚动column到它。有一个方法在scrollStatescrollState.smoothScrollTo(0f),但我不知道如何获得一个聚焦的TextField位置。

更新:

我似乎找到了一个可行的解决方案。我用过onGloballyPositioned,它是有效的。但我不确定这是否是解决这个问题的最好方法。
var scrollToPosition = 0.0F
TextField(
modifier = Modifier
.focusOrder(countryFocus)
.onGloballyPositioned { coordinates ->
scrollToPosition = scrollState.value + coordinates.positionInRoot().y
}
.onFocusChanged {
if (it == FocusState.Active) {
scope.launch {
scrollState.smoothScrollTo(scrollToPosition)
}
}
}
)

有一种新的东西叫做RelocationRequester。这就解决了我的问题。在我的自定义TextField中有这样的东西

val focused = source.collectIsFocusedAsState()
val relocationRequester = remember { RelocationRequester() }
val ime = LocalWindowInsets.current.ime
if (ime.isVisible && focused.value) {
relocationRequester.bringIntoView()
}

也可以使用BringIntoViewRequester

//
val bringIntoViewRequester = remember { BringIntoViewRequester() }
val coroutineScope = rememberCoroutineScope()
//--------
TextField( ..., modifier = Modifier.bringIntoViewRequester(bringIntoViewRequester)
.onFocusEvent {
if (it.isFocused) {
coroutineScope.launch {
bringIntoViewRequester.bringIntoView()
}
}
}

似乎使用LazyColumnLazyListState.animateScrollToItem()而不是Column可能是您的情况下一个很好的选择。

参考:https://developer.android.com/jetpack/compose/lists control-scroll-position

顺便感谢您提供的onGloballyPositioned()修饰语信息。我在寻找正常Column情况下的解决方案。这节省了我很多时间!

下面是我用来确保表单中的字段不会被键盘切断的一些代码:

From: stack overflow -当键盘打开时检测

enum class Keyboard {
Opened, Closed
}
@Composable
fun keyboardAsState(): State<Keyboard> {
val keyboardState = remember { mutableStateOf(Keyboard.Closed) }
val view = LocalView.current
DisposableEffect(view) {
val onGlobalListener = ViewTreeObserver.OnGlobalLayoutListener {
val rect = Rect()
view.getWindowVisibleDisplayFrame(rect)
val screenHeight = view.rootView.height
val keypadHeight = screenHeight - rect.bottom
keyboardState.value = if (keypadHeight > screenHeight * 0.15) {
Keyboard.Opened
} else {
Keyboard.Closed
}
}
view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalListener)
onDispose {

view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalListener)
}
}
return keyboardState
}

,然后在我的可组合:

val scrollState = rememberScrollState()
val scope = rememberCoroutineScope()
val isKeyboardOpen by keyboardAsState()
if (isKeyboardOpen == Keyboard.Opened) {
val view = LocalView.current
val screenHeight = view.rootView.height
scope.launch { scrollState.scrollTo((screenHeight * 2)) }
}
Surface(modifier = Modifier
.fillMaxHeight()
.verticalScroll(scrollState),

)  {
//Rest of your Composables, Columns, Rows, TextFields, Buttons
//add this so the screen can scroll up and keyboard cannot cover the form fields - Important!
/*************************************************/
if (isKeyboardOpen == Keyboard.Opened) {
Spacer(modifier = Modifier.height(140.dp))
}
}

希望能帮到别人。我用的是:

val bringIntoViewRequester = remember { BringIntoViewRequester() }
val scope = rememberCoroutineScope()
val view = LocalView.current
DisposableEffect(view) {
val listener = ViewTreeObserver.OnGlobalLayoutListener {
scope.launch { bringIntoViewRequester.bringIntoView() }
}
view.viewTreeObserver.addOnGlobalLayoutListener(listener)
onDispose { view.viewTreeObserver.removeOnGlobalLayoutListener(listener) }
}
Surface(modifier.bringIntoViewRequester(bringIntoViewRequester)) {
///////////rest of my composables
}

但这行不通。

最新更新