почему я не могу использовать scrollToEnd или подобные функции в моем проекте Jetpack Compose?
Я пытаюсь перейти к последнему элементу ленивого столбца, потому что у меня есть ленивый столбец и пустой список. Приложение, которое я сделал, является приложением чат-бота, есть сообщения бота и сообщения пользователя. Когда бот дает сообщение, оно добавляется в , в то же время, когда пользователь вводит ответ, оно добавляется в , и по мере добавления в этот пустой список начинает заполняться, а также отображается ленивый столбец , но это отдельная вещь, которая должна быть в заочном приложении. По мере добавления сообщений, то есть при достижении конца экрана, экран должен скользить вниз. Я использовал или что-то подобное, чтобы сделать это, но мой проект не видитscrollToEnd
и выдает следующую ошибкуUnresolved reference: scrollToEnd
или напримерisScrolledToEnd()
Когда я использую это, мне интересно, есть ли отдельный элемент, который я должен добавить. Есть ли зависимость или они устарели? вы можете помочь мне решить эту проблему
var index = 1
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun FirstScreen() {
val list = remember { mutableStateListOf<Message>() }
val UserList = remember { mutableStateListOf<Message>() }
val botList = listOf("Peter", "Francesca", "Luigi", "Igor")
val random = (0..3).random()
val botName: String = botList[random]
val hashMap: HashMap<String, String> = HashMap<String, String>()
val coroutineScope = rememberCoroutineScope()
customBotMessage(message = Message1, list)
Column(modifier = Modifier.fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top) {
Image(
painter = painterResource(id = R.drawable.diyetkolik_logo),
contentDescription = "logo",
modifier = Modifier.padding(10.dp)
)
Divider()
val listState = rememberLazyListState()
LazyColumn(modifier = Modifier.fillMaxSize(),
state = listState) {
println("size:"+list.size)
items(list.size) { i ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement =
if (list[i].id == RECEIVE_ID)
Arrangement.Start
else
Arrangement.End
) {
if (list[i].id == RECEIVE_ID) {
Item(
message = list[i],
botName,
botcolor,
list,
simpleTextFlag = true,
hashMap,
modifier = Modifier
.padding(
start = 32.dp,
end = 4.dp,
top = 4.dp
),
)
} else {
Item(
message = list[i],
"user",
usercolor,
UserList,
simpleTextFlag = false,
hashMap,
Modifier.padding(
start = 4.dp,
end = 32.dp,
top = 4.dp
)
)
}
}
}
}
val endOfListReached = remember {
derivedStateOf {
listState.isAtBottom() // error occurs @Composable invocations can only happen from the context of a @Composable function
}
}
// act when end of list reached
LaunchedEffect(endOfListReached) {
// do your stuff
}
}
}
private fun customBotMessage(message: String, list: SnapshotStateList<Message>) {
GlobalScope.launch {
delay(1000)
withContext(Dispatchers.Main) {
list.add(
Message(
message,
RECEIVE_ID,
Timestamp(System.currentTimeMillis()).toString()
)
)
}
}
}
@Composable
fun Item(
message: Message,
person: String,
color: Color,
list: SnapshotStateList<Message>,
simpleTextFlag: Boolean,
hashMap: HashMap<String, String>,
modifier: Modifier
) {
Column(verticalArrangement = Arrangement.Top) {
Card(
modifier = Modifier
.padding(10.dp),
backgroundColor = color,
elevation = 10.dp
) {
Row(
verticalAlignment = Alignment.Top,
modifier = Modifier.padding(3.dp)
) {
Text(
buildAnnotatedString {
withStyle(
style = SpanStyle(
fontWeight = FontWeight.Medium,
color = Color.Black
)
) {
append("$person: ")
}
},
modifier = Modifier
.padding(4.dp)
)
Text(
buildAnnotatedString {
withStyle(
style = SpanStyle(
fontWeight = FontWeight.W900,
color = Color.White//Color(/*0xFF4552B8*/)
)
)
{
append(message.message)
}
}
)
}
}
if (simpleTextFlag)
SimpleText(list = list, hashMap)
}
}
@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
@Composable
fun SimpleText(list: SnapshotStateList<Message>, hashMap: HashMap<String, String>) {
val coroutineScope = rememberCoroutineScope()
val keyboardController = LocalSoftwareKeyboardController.current
val bringIntoViewRequester = remember { BringIntoViewRequester() }
var visible by remember { mutableStateOf(true) }
var text by remember { mutableStateOf("") }
AnimatedVisibility(
visible = visible,
enter = fadeIn() + slideInHorizontally(),
exit = fadeOut() + slideOutHorizontally()
) {
Row(
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.End,
modifier = Modifier.bringIntoViewRequester(bringIntoViewRequester)
) {
OutlinedTextField(
modifier = Modifier
.padding(2.dp)
.onFocusEvent { focusState ->
if (focusState.isFocused) {
coroutineScope.launch {
bringIntoViewRequester.bringIntoView()
}
}
},
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { keyboardController?.hide() }),
value = text,
onValueChange = { text = it },
shape = RoundedCornerShape(12.dp),
label = { Text("send message") })
IconButton(onClick = {
if (text.isNotEmpty()) {
//Adds it to our local list
list.add(
Message(
text,
Constants.SEND_ID,
Timestamp(System.currentTimeMillis()).toString()
)
)
hashMap.put(Messages.listOfMessageKeys[index - 1], text)
customBotMessage(listOfMessages[index], list)
index += 1
visible = false
}
text = ""
}) {
Icon(
modifier = Modifier.padding(2.dp),
painter = painterResource(id = R.drawable.ic_baseline_send_24),
contentDescription = "send message img"
)
}
}
}
}
private fun customBotMessage(message: String, list: SnapshotStateList<Message>) {
GlobalScope.launch {
delay(1000)
withContext(Dispatchers.Main) {
list.add(
Message(
message,
Constants.RECEIVE_ID,
Timestamp(System.currentTimeMillis()).toString()
)
)
}
}
}
Я знаю, что это плохо написанный код, и у вас могут возникнуть проблемы с его пониманием, поэтому я объясню, как этот код работает для вас. Вкратце, первый экран, который открывается, это FirstScreen, и есть пустой список, который я определил здесь, и под пустым списком я подразумеваюval list = remember { mutableStateListOf<Message>() }
на первом экране. Во-первых, я звоню вcustomBotMessage
для взаимодействия с пользователем и добавляет первое сообщение в подготовленный мной список сообщений. При добавлении в , он попадает в ленивую колонку и отображается на экране как .
При переходе к , есть окно сообщения в и текстовое поле сразу под окном сообщения, где пользователь может ввести ввод, если сообщение, входящее вItem
это пользовательское сообщение, показать это текстовое поле ввода. Я проверил это с помощьюid
вif
состояния в ленивом столбце в FirstScreen, вы можете понять, если посмотрите на файл FirstScreen. И когда пользователь вводит значение в это текстовое поле ввода, оно добавляется туда же и отображается на экране, но по мере добавления сообщений в полеlist
, я хочу, чтобы экран прокручивался вниз, как я сказал выше, как я могу сделать это в своем коде?
РЕДАКТИРОВАТЬ
@GabrieleMarriotti
Спасибо за ваш ответ, но я думаю, что не объяснил точно, что я хотел, или я не понял, извините. У меня есть список, и сообщения добавляются в этот список по порядку, и по мере добавления они появляются на экране, поэтому у меня нет 100 сообщений в списке одновременно. Как и в приложении для переписки, сообщения скользят по экрану вниз, а когда доходят до нижней части экрана, последние добавленные сообщения не видны. Я хочу, чтобы пользователь мог видеть последнее добавленное сообщение, то есть экран прокручивался вниз, чтобы пользователь мог видеть последнее добавленное сообщение. Я сделал ответ, который вы дали, но он дал следующую ошибку
@Composable invocations can only happen from the context of a @Composable function
и я не мог точно понять, как использовать его в моем вопросе. Если ваш ответ является последним индексом, он возвращает true, в противном случае он возвращает false. Если это именно ответ на мой вопрос, я не мог понять, как и где его использовать в моем коде. Может ли это быть проблемой с lazycolumn, потому что lazycolumn не должен выполнять эту задачу автоматически? спасибо за Ваш ответ
1 ответ
Пожалуйста, установитеLayColumn
, вам не нужно вызывать scrollToEnd, вы добавляете в список, последние новости будут отображаться автоматически:
LazyColumn(
reverseLayout = true,
state = listState,
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top) {
// do something....
}