Wen Zhe
Wen Zhe

Reputation: 33

How to scroll lazy column when soft keyboard is called?

I am trying to implement a chat function in my app. I am dealing with the elements being pushed upwards when the keyboard is called. Right now what seems to be working the closest to what I want is setting android:windowSoftInputMode="adjustNothing", adding imePadding and windowInsets since I'm using a Scaffold. However, the padding for the chat box lazy columns move but not the contents. I tried using offset y instead but I'm not really sure how to retrieve the height of the keyboard.

Box(
    Modifier
        .padding(top = 10.dp)
        .fillMaxSize()
        .consumeWindowInsets(padding)
        .imePadding()
        .zIndex(0.5f)
) {

    var listState = rememberLazyListState()
    val coroutineScope = rememberCoroutineScope()
    var textBoxList = remember {
        mutableStateListOf(
            TextBoxData("This is the first message", "Bot"),
            TextBoxData("This is the second message", "User"),
            TextBoxData("This is the first message", "Bot"),
            TextBoxData("This is the second message", "User"),
            TextBoxData("This is the last message", "User")
        )
    }

    // LazyColumn for chat
    LazyColumn(
        Modifier
            .fillMaxSize()
            .padding(bottom = 50.dp),
        state = listState
    ) {
        //For Each, Map
        items(textBoxList) { item ->
            TextBox(item)
        }

    }

    // Bottom Input Bar
    Box(
        Modifier
            .align(Alignment.BottomCenter)
            .fillMaxWidth()
            .height(50.dp)
            .clip(RoundedCornerShape(20.dp))
            .background(Black)
            .border(2.dp, White, RoundedCornerShape(20.dp))
    ) {
        Row(
            Modifier.fillMaxSize(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Icon(
                imageVector = FeatherIcons.Mic,
                "Microphone Icon",
                tint = White,
                modifier = Modifier
                    .fillMaxHeight()
                    .padding(start = 10.dp)
            )

            // Text Field Here
            var inputText by remember { mutableStateOf("") }
            var textFieldScrollState = rememberScrollState(10)
            var lineWidth = 255.dp
            var textWidth = measureTextWidth(
                inputText,
                TextStyle(
                    fontSize = 16.sp,
                    fontFamily = RalewayRegular
                )
             )

             // Configure the Alignment and Scroll State
             TextField(
                 value = inputText,
                 onValueChange = {
                     inputText = it
                     val currLine = (textWidth / lineWidth).toInt()
                     coroutineScope.launch {
                         textFieldScrollState.scrollTo(
                             // Dont scroll if on first line (Default is 0)
                             if (currLine == 0) 5 else textFieldScrollState.maxValue - 5)
                             Log.i("TextSize", listState.layoutInfo.viewportEndOffset.toString())
                     }
                 },
                 placeholder = {
                     Text(
                         "Type Something...",
                         color = White.copy(0.7f),
                         fontSize = 16.sp,
                         lineHeight = 16.sp,
                         fontFamily = RalewayRegular
                     )
                 },
                 textStyle = TextStyle(
                     color = White,
                     fontSize = 16.sp,
                     fontFamily = RalewayRegular,
                     textAlign = TextAlign.Start,
                 ),
                 modifier = Modifier
                     .width(290.dp)
                     .fillMaxHeight()
                     .padding(start = 10.dp)
                     .verticalScroll(textFieldScrollState),
                 colors = TextFieldDefaults.colors(
                     focusedTextColor = White,
                     unfocusedTextColor = White,
                     unfocusedContainerColor = Black,
                     focusedContainerColor = Black
                 )
             )

             val regex_space = Regex("^\\s*\$") // \\s* means unlimited number of empty (\\s)
             Icon(
                 imageVector = FeatherIcons.Send,
                 contentDescription = "Send button",
                 tint = White,
                 modifier = Modifier
                     .fillMaxHeight()
                     .padding(start = 10.dp)
                     .clickable {
                         if (!inputText.matches(regex_space)) {
                             textBoxList.add(TextBoxData(inputText, "User"))
                             inputText = ""
                             //Use Coroutine Scope to Scroll
                             //LazyColumn needs items(textBoxList) to scroll to the item index
                             coroutineScope.launch {
                                 listState.scrollToItem(textBoxList.size - 1)
                            }
                        }
                    }
                )
            }
        }
    }
}

Upvotes: 1

Views: 31

Answers (0)

Related Questions