androidkotlinandroid-jetpack-compose

How to apply onTextLayout to OutlinedTextField in Jetpack Compose?


I wrote code that keeps the focused TextField always visible above the keyboard using BasicTextField.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CustomTextField(
    value: String,
    onValueChange: (String) -> Unit
    ) {
    val bringIntoViewRequester = remember { BringIntoViewRequester() }
    val coroutineScope = rememberCoroutineScope()

    var textFieldValue by remember { mutableStateOf(TextFieldValue(value)) }

    BasicTextField(
        value = textFieldValue,
        onValueChange = {
            textFieldValue = it
            onValueChange(it.text)
        },
        onTextLayout = {
            val cursorRect = it.getCursorRect(textFieldValue.selection.start)
            coroutineScope.launch {
                bringIntoViewRequester.bringIntoView(cursorRect)
            }
        },
        modifier = Modifier.bringIntoViewRequester(bringIntoViewRequester)
    )
}

I'm trying to apply this to OutlinedTextField, but unfortunately, it doesn't seem to be compatible with OutlinedTextField.
So, I tried using OutlinedTextField with decorationBox, but this approach was unsuccessful.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CustomTextField(
    value: String,
    textStyle: TextStyle,
    modifier: Modifier,
    onValueChange: (String) -> Unit
) {
    val bringIntoViewRequester = remember { BringIntoViewRequester() }
    val coroutineScope = rememberCoroutineScope()

    var textFieldValue by remember { mutableStateOf(TextFieldValue(value)) }

    BasicTextField(
        value = textFieldValue,

        onValueChange = {
            textFieldValue = it
            onValueChange(it.text)
        },
        onTextLayout = {
            val cursorRect = it.getCursorRect(textFieldValue.selection.start)
            coroutineScope.launch {
                bringIntoViewRequester.bringIntoView(cursorRect)
            }
        },
        decorationBox = @Composable { innerTextField ->
            OutlinedTextField(
                value = textFieldValue.text,
                onValueChange = {},
                modifier = modifier.fillMaxWidth(),
                textStyle = textStyle,
            )
            innerTextField()
        },
        modifier = Modifier.bringIntoViewRequester(bringIntoViewRequester)
    )
}

Could you please provide some advice?


Solution

  • I think they are designed for different purposes. So you can use just OutlineTextField without BasicTextField

    Something like that:

    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun CustomOutlinedTextField(
        value: String,
        onValueChange: (String) -> Unit,
        textStyle: TextStyle = TextStyle.Default,
        modifier: Modifier = Modifier
    ) {
        val bringIntoViewRequester = remember { BringIntoViewRequester() }
        val coroutineScope = rememberCoroutineScope()
    
        OutlinedTextField(
            value = value,
            onValueChange = { newValue ->
                onValueChange(newValue)
                coroutineScope.launch {
                    bringIntoViewRequester.bringIntoView()
                }
            },
            textStyle = textStyle,
            modifier = modifier
                .bringIntoViewRequester(bringIntoViewRequester)
        )
    }