List of AutoCompleteTextField not visible (is drawing behind softKeyboard)

46 Views Asked by At

I have a problem, which I cannot solve ...

I have a activity where the user could add some information like name and so one. It is written in Kotlin with the Jetpack Compose library. One field is an AutoCompleteTextView where the systems gets information from a room database and display the stuff on a list below the textField. My problem is that this list is always shown behind the keyboard. (as show in the pictures below). How can I manage that the list is shown / scrolled into view? (the "InputFields" are located inside a scrollable column). When displaying the list above the textField then there is another problem: I lost the focus of the textField ...

Without List

List is not shown/scrolled

How it should be

My Code:

AutoCompleteView:

@Composable
fun <T> AutoCompleteTextView(
modifier: Modifier,
value: String,
label: String,
onValueChanged: (String) -> Unit = {},
predictions: List<T>,
clearVisible: Boolean = true,
keyBoardAction: ImeAction = ImeAction.Search,
onActionClick: () -> Unit = {},
onClearClick: () -> Unit = {},
onItemClick: (T) -> Unit = {},
itemContent: @Composable (T) -> Unit = {},
) {
val view = LocalView.current
val lazyListState = rememberLazyListState()
var showClearButton by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
LazyColumn(
    state = lazyListState,
    modifier = modifier.heightIn(max = TextFieldDefaults.MinHeight * 6)
) {

    item {
        OutlinedTextField(
            modifier = modifier
                .onFocusChanged { focusState ->
                    showClearButton = clearVisible and focusState.isFocused
                }
                .focusRequester(focusRequester),
            value = value,
            onValueChange = {
                onValueChanged.invoke(it)
                focusRequester.requestFocus()
            },
            label = { Text(text = label) },
            singleLine = true,
            trailingIcon = {
                if (showClearButton) {
                    IconButton(painterResource(R.mipmap.ic_close), 
                    stringResource(R.string.clear)) {
                        onClearClick()
                    }
                }
            },
            keyboardActions = KeyboardActions(
                onSearch = { onActionClick() },
                onDone = { onActionClick() },
                onGo = { onActionClick() },
                onNext = { onActionClick() },
                onPrevious = { onActionClick() },
                onSend = { onActionClick() },
            ),
            keyboardOptions = KeyboardOptions(
                imeAction = keyBoardAction,
                keyboardType = KeyboardType.Text
            ),
            shape = RoundedCornerShape(10.dp),
            colors = TextFieldDefaults.colors(
                focusedIndicatorColor = MaterialTheme.colorScheme.primaryContainer,
                unfocusedIndicatorColor = 
MaterialTheme.colorScheme.secondaryContainer,
                focusedContainerColor = Color.Transparent,
                unfocusedContainerColor = Color.Transparent,
                errorContainerColor = Color.Transparent
            )
        )
    }

    if (predictions.isNotEmpty()) {
        itemsIndexed(predictions) { _, element ->
            Row(
                Modifier
                    .padding(5.dp)
                    .fillMaxWidth()
                    .clickable {
                        view.clearFocus()
                        onItemClick(element)
                    }
            ) {
                itemContent(element)
            }
        }
    }
  }
}

Activity:

   Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(5.dp)
                ) {
                    Surface(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(top = 10.dp),
                        shape = RoundedCornerShape(10.dp),
                        border = BorderStroke(1.dp, 
   MaterialTheme.colorScheme.secondaryContainer)
                    ) {
                        Column {
                            Row(modifier = Modifier.wrapContentWidth()) {
                                Image(
                                    modifier = Modifier
                                        .verticalGradient()
                                        .padding(start = 15.dp, top = 20.dp, end = 
   10.dp)
                                        .size(24.dp),
                                    painter = painterResource(R.mipmap.ic_dice),
                                    contentDescription = 
   stringResource(R.string.genres)
                                )
                                Column(modifier = Modifier.wrapContentSize()) {
                                    FlowRow(
                                        modifier = Modifier
                                            .wrapContentSize()
                                            .padding(vertical = 6.dp),
                                        horizontalArrangement = 
  Arrangement.spacedBy(5.dp, Start),
                                        verticalArrangement = Arrangement.Top
                                    ) {
                                        for (genre in genres) {
                                            FilterChip(
                                                modifier = Modifier.padding(horizontal 
   = 5.dp),
                                                onClick = { genres.remove(genre) },
                                                selected = true,
                                                trailingIcon = {
                                                    Image(
                                                        modifier = Modifier
                                                            .verticalGradient()
                                                            .size(15.dp),
                                                        painter = 
   painterResource(R.mipmap.ic_close),
                                                        contentDescription = 
   stringResource(R.string.delete)
                                                    )
                                                },
                                                label = {
                                                    Text(genre.name)
                                                }
                                            )
                                        }
                                    }
                                    Box(
                                        Modifier
                                            .fillMaxWidth()
                                            .padding(horizontal = 10.dp)
                                            .height(1.dp)
                                            
   .background(MaterialTheme.colorScheme.secondaryContainer)
                                    )
                                    AutoCompleteTextView(modifier = 
   Modifier.padding(5.dp),
                                        value = selectedGenreName,
                                        label = "Genre",
                                        onValueChanged = {
                                            selectedGenreName = it
                                            if (it.isNotEmpty()) {
                                                getGenres(it)
                                            } else {
                                                filteredGenres.clear()
                                            }
                                        },
                                        predictions = filteredGenres,
                                        keyBoardAction = ImeAction.Done,
                                        clearVisible = false,
                                        onActionClick = {
                                            val first = filteredGenres.stream().filter 
   { it.name == selectedGenreName }.findFirst()
                                            if (first.isPresent) {
                                                genres.add(first.get())
                                            } else {
                                                genres.add(Genre().apply { name = 
   selectedGenreName })
                                            }
                                            selectedGenreName = ""
                                            filteredGenres.clear()
                                        },
                                        onItemClick = {
                                            genres.add(it)
                                            selectedGenreName = ""
                                            filteredGenres.clear()
                                        }) {
                                        Text(text = it.name)
                                    }
                                }
                            }
                        }
                    }
                    Surface(
                        modifier = Modifier.padding(start = 15.dp),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        Text(
                            modifier = Modifier
                                .padding(horizontal = 5.dp)
                                .horizontalGradient(),
                            text = stringResource(R.string.genres),
                            fontSize = 14.sp
                        )
                    }
                }
2

There are 2 best solutions below

1
Mahmoud Ewida On

You can add this line android:windowSoftInputMode="adjustResize" to the activity tag that holds this screen on the manifest file and the keyboard will push the screen up

0
Sebi On

I have managed it (with a little 'hack')

For this solution to get work I had to placed the Box at the end of the scrollable column.

Then I had to add:

android:windowSoftInputMode="adjustResize" 

to the manifest (to the activity I used) and had to add:

Modifier.imePadding()

to the scrollable column (in order to put the bottom of the column to the top of the keyboard)

Then on recompose the autocomplete view I set

 scope.launch { scrollState.animateScrollTo(scrollState.maxValue) }

So it always scroll to the end and so the list is visible.