В ряде приложений применяется кнопка перемещение в начало контента, то есть фактически кнопка прокрутки в начало. Посмотрим, как сделать такую кнопку на Jetpack Compose. Для этого рассмотрим следующее приложение:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.ui.unit.sp import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val listState = rememberLazyListState() val coroutineScope = rememberCoroutineScope() val displayButton =remember { derivedStateOf { listState.firstVisibleItemIndex > 5 } } Box(Modifier.fillMaxSize()) { LazyColumn(state = listState) { items(30) { Text("Item $it", Modifier.padding(8.dp), fontSize = 28.sp) } } AnimatedVisibility(visible = displayButton.value, Modifier.align(Alignment.BottomCenter) ) { OutlinedButton( onClick = { coroutineScope.launch { listState.scrollToItem(0) } }, border = BorderStroke(1.dp, Color.Gray), shape = RoundedCornerShape(50), colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.DarkGray), modifier = Modifier.padding(5.dp) ) { Text("Top", fontSize = 22.sp) } } } } } }
Для управления прокруткой списка применяется состояние LazyListState:
val listState = rememberLazyListState()
Поскольку функции программной прокрутки представляют suspend-функции, и соответственно их надо запускать из корутин, то для программной прокрутки определятся область корутины:
val coroutineScope = rememberCoroutineScope()
И также определяется производное состояние, которое указывает, будет ли отображаться кнопка прокрутки:
val displayButton =remember { derivedStateOf { listState.firstVisibleItemIndex > 5 } }
В данном случае мы говорим, что этот состояние будет равно true, если индекс первого видимого элемента в списке больше 5. А это значит, что кнопка прокрутки будет отображаться. Если же мы находимся в самом начале списка (индекс первого видимого элемента в списке равен или меньше 5), то нет смысла отображать кнопку прокрутки, поэтому это состояние будет равно false.
Для хранения всего интерфейса определяется компонент Box. Здесь список, для которого определяется прокрутка, определен в компоненте LazyList. В данном случае это просто 30 компонентов Text:
LazyColumn(state = listState) { items(30) { Text("Item $it", Modifier.padding(8.dp), fontSize = 28.sp) } }
Также в Box располагается элемент AnimatedVisibility, который представляет анимацию видимости и будет управлять видимостью кнопки:
AnimatedVisibility(visible = displayButton.value, Modifier.align(Alignment.BottomCenter)) { OutlinedButton( onClick = { coroutineScope.launch { listState.scrollToItem(0) } }, border = BorderStroke(1.dp, Color.Gray), shape = RoundedCornerShape(50), colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.DarkGray), modifier = Modifier.padding(5.dp) ) { Text("Top", fontSize = 22.sp) } }
Этот компонент будет накладываться на список LazyList, но благодаря состоянию displayButton, которое зависит от индекса первого видимого элемента списка, мы сможем автоматически и динамически управлять видимостью этого компонента.
Непосредственно сама кнопка представлена компонентом OutlinedButton - кнопкой, по нажатию на которую происходит запуск корутины, в которой выполняется переход в начало списка
с помощью вызова listState.scrollToItem(0)
Таким образом, если мы уйдем вниз по списку, то мы увидим кнопку возврата в начало списка: