英文:
How to prevent a gap between the keyboard and a bottom-aligned button in Android Jetpack Compose?
问题
你可以尝试在你的代码中使用Modifier.fillMaxHeight()来确保按钮始终位于屏幕底部,并且在键盘打开时与键盘一起上移,关闭时下移。在以下的代码片段中,我已经添加了这个修饰符:
Column(
    modifier = Modifier
        .fillMaxSize()
        .imePadding()
        .semantics { contentDescription = screenDescription },
    verticalArrangement = Arrangement.SpaceBetween,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    // ... 省略其余的代码
    Column(
        modifier = Modifier
            .weight(0.20f, fill = true)
            .fillMaxWidth()
            .fillMaxHeight() // 这里添加了Modifier.fillMaxHeight()
    ) {
        Crossfade(targetState = isInError, label = "isInErrorButton") { isInError ->
            Button(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(48.dp),
                shape = RectangleShape,
                colors = if (isInError) {
                    ButtonDefaults.buttonColors(containerColor = Color.Red)
                } else {
                    ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary)
                },
                onClick = {
                    hapticGenerator.performHapticFeedback(HapticFeedbackType.LongPress)
                    if (validateInput()) {
                        focusManager.clearFocus()
                        onContinueButtonClick()
                        navigateToNextScreen()
                    }
                }
            ) {
                Text(
                    modifier = Modifier.padding(horizontal = 16.dp),
                    text = "Continue",
                    style = MaterialTheme.typography.bodyLarge
                )
            }
        }
    }
}
这个修饰符应该帮助你解决键盘打开和关闭时出现的间隙问题。希望这对你有所帮助!
英文:
I want to have a button that is always at the bottom of the screen, when the keyboard opens it should go up with it and when it closes the button should go down again.
I tried different ways, with a Box wrapping everything and different configurations of nested Columns.
But sometimes after closing and opening the keyboard there is a gap between the keyboard and the button.
How do I fix that?
This is my current code:
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PlayerNameSelectionScreenContent(
    playerName: TextFieldValue,
    onChangePlayerName: (TextFieldValue) -> Unit = {},
    onContinueButtonClick: () -> Unit = {},
    navigateToNextScreen: () -> Unit = {},
    validateInput: () -> Boolean = { false },
    isInError: Boolean = false,
    errorMessage: String = ""
) {
    val focusManager = LocalFocusManager.current
    val focusRequester = remember { FocusRequester() }
    val hapticGenerator = LocalHapticFeedback.current
    val screenDescription = "Player Name Selection Screen"
    Column(
        modifier = Modifier
            .fillMaxSize()
            .imePadding()
            .semantics { contentDescription = screenDescription },
        verticalArrangement = Arrangement.SpaceBetween,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Column(
            modifier = Modifier
                .weight(0.40f, true)
                .fillMaxWidth(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Spacer(modifier = Modifier.size(32.dp))
            Text(
                text = "Player Setup",
                style = MaterialTheme.typography.displayMedium,
                textAlign = TextAlign.Center
            )
            Spacer(modifier = Modifier.size(16.dp))
            Text(
                text = "Player 1",
                style = MaterialTheme.typography.headlineLarge,
                textAlign = TextAlign.Center
            )
            Spacer(modifier = Modifier.size(8.dp))
            Text(
                text = "Start with yourself and proceed in storm order.",
                style = MaterialTheme.typography.bodyLarge,
                textAlign = TextAlign.Center
            )
        }
        Column(
            modifier = Modifier
                .weight(0.40f)
                .fillMaxWidth(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Spacer(modifier = Modifier.size(64.dp))
            Text(
                text = "Set the player name:",
                style = MaterialTheme.typography.headlineSmall,
                textAlign = TextAlign.Center
            )
            Spacer(modifier = Modifier.size(16.dp))
            val textFieldDescription = "Player name text field"
            OutlinedTextField(
                modifier = Modifier
                    .focusRequester(focusRequester)
                    .semantics {
                        contentDescription = textFieldDescription
                        setText { text ->
                            onChangePlayerName(TextFieldValue(text.text))
                            true
                        }
                        testTag = "PlayerName"
                        testTagsAsResourceId = true
                    },
                value = playerName,
                onValueChange = onChangePlayerName,
                label = { Text(stringResource(id = R.string.name_text)) },
                placeholder = { Text(stringResource(id = R.string.name_text)) },
                singleLine = true,
                isError = isInError,
                keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
                keyboardOptions = KeyboardOptions.Default.copy(
                    imeAction = ImeAction.Done,
                    keyboardType = KeyboardType.Text
                )
            )
            Spacer(modifier = Modifier.size(8.dp))
            val errorMessageDescription =
                stringResource(id = R.string.error_message_description)
            Crossfade(targetState = isInError, label = "isInErrorText") { isInError ->
                Text(
                    modifier = Modifier.semantics {
                        contentDescription = errorMessageDescription
                    },
                    text = if (isInError) errorMessage else "",
                    style = MaterialTheme.typography.bodyLarge,
                    textAlign = TextAlign.Center,
                    color = Color.Red,
                    minLines = 2
                )
            }
        }
        Column(
            modifier = Modifier
                .weight(weight = 0.20f, fill = true)
                .fillMaxWidth(),
            verticalArrangement = Arrangement.Bottom
        ) {
            Crossfade(targetState = isInError, label = "isInErrorButton") { isInError ->
                Button(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(48.dp),
                    shape = RectangleShape,
                    colors = if (isInError) {
                        ButtonDefaults.buttonColors(containerColor = Color.Red)
                    } else {
                        ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary)
                    },
                    onClick = {
                        hapticGenerator.performHapticFeedback(HapticFeedbackType.LongPress)
                        if (validateInput()) {
                            focusManager.clearFocus()
                            onContinueButtonClick()
                            navigateToNextScreen()
                        }
                    }
                ) {
                    Text(
                        modifier = Modifier.padding(horizontal = 16.dp),
                        text = "Continue",
                        style = MaterialTheme.typography.bodyLarge
                    )
                }
            }
        }
    }
    LaunchedEffect(key1 = Unit) {
        focusRequester.requestFocus()
        onChangePlayerName(TextFieldValue(playerName.text, TextRange(playerName.text.length)))
    }
}
Here is how it looks:
Screen Screenshot
And here is a gif that shows what happens if I open and close the keyboard:
Open Keyboard Gif
I tried wrapping everything with a box that has the modifier fillMaxSize and then a Column in it with Arrangement.Bottom in that configuration the gap between the keyboard and button could appear.
Then I tried a few different configurations of the mentioned code with different nestings of the Columns.
I also tried adding or removing the imePadding modifier on the different Boxes or Columns.
答案1
得分: 0
我已经尝试了一些并且认为我找到了一个解决方案:
- 我已经在AndroidManifest.xml文件的activity部分中添加了android:windowSoftInputMode="adjustResize"。
 
<activity
    android:name="..."
    android:windowSoftInputMode="adjustResize"
    ... 
</activity>
- 我有三列,我在前两列中添加了修饰符".weight(0.50f)",并从最后一列中移除了weight修饰符。
 
英文:
I have tried a bit more and think I found a solution:
- I have added android:windowSoftInputMode="adjustResize" to the activity section in the AndroidManifest.xml.
 
<activity
    android:name="..."
    android:windowSoftInputMode="adjustResize"
    ... 
</activity>
- I have three columns, I added the modifier 
.weight(0.50f)to the first two columns and removed the weight modifier from the last column. 
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论