關于如何在加載項目時實現滑動刷新功能以及占位符的簡短指南
今天,許多應用程序都有需要在某個時候刷新的數據。 您可以在一段時間後刷新數據或使用套接字來始終擁有最新的數據,但是如果您想要允許用戶開始刷新數據的功能怎麼辦?
這可以通過一個按鈕來完成,但在某些情況下,更好的用戶體驗将是滑動刷新。 今天,我們将使用 Accompanist 庫來實現它。
滑動刷新
首先,讓我們添加一個依賴項:
implementation "com.google.accompanist:accompanist-swiperefresh:0.25.1"
注意:檢查是否有此依賴項的更新版本。
接下來是創建一個簡單的ViewModel,它将保存我們的數據和刷新邏輯。 在這裡,項目将包含随機圖像和數字。 這是它的樣子:
class MainViewModel : ViewModel() {
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing = _isRefreshing.asStateFlow()
private val _currentTime = MutableStateFlow(Instant.now())
val currentTime = _currentTime.asStateFlow()
private val _items = MutableStateFlow(generateItems())
val items = _items.asStateFlow()
fun refresh() = viewModelScope.launch {
_isRefreshing.update { true }
// Simulate API call
delay(2000)
_currentTime.value = Instant.now()
_items.value = generateItems()
_isRefreshing.update { false }
}
private fun generateItems(): List<RowItem> {
val list = mutableListOf<RowItem>()
for (i in 1 until 20) {
list.add(
RowItem(
rowImage = randomImage(),
number = Random.nextInt(1, 1000)
)
)
}
return list
}
private fun randomImage(
seed: Int = (0..100000).random(),
width: Int = 300,
height: Int = width,
): String {
return "https://picsum.photos/seed/$seed/$width/$height"
}
}
data class RowItem(
val rowImage: String = "",
val number: Int = -1
)
isRefreshing 是一個布爾值,我們将在 swipeRefreshState 中使用它,我們将在後面解釋。 items 隻是包含随機圖像和數字的 20 個項目的列表。
現在,讓我們創建我們的屏幕:
@Composable
fun MainScreen(
viewModel: MainViewModel = viewModel()
) {
val isRefreshing = viewModel.isRefreshing.collectAsState().value
val currentTime = viewModel.currentTime.collectAsState().value
val items = viewModel.items.collectAsState().value
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = isRefreshing)
SwipeRefresh(
state = swipeRefreshState,
onRefresh = viewModel::refresh,
modifier = Modifier
.fillMaxSize()
.padding(
vertical = 32.dp,
horizontal = 16.dp
)
) {
Column {
Text(
text = "Welcome to Swipe-to-Refresh!",
style = MaterialTheme.typography.h5,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = currentTime.toString(),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.End
)
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items) {
Item(
rowItem = it
)
}
}
}
}
}
@Composable
fun Item(
rowItem: RowItem
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
elevation = 4.dp
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = rememberAsyncImagePainter(rowItem.rowImage),
contentDescription = rowItem.number.toString(),
modifier = Modifier.size(64.dp)
)
Spacer(modifier = Modifier.width(16.dp))
Text(text = "Number: ${rowItem.number}")
}
}
}
我們正在收集我們的狀态并使用 isRefreshing 的值創建 swipeRefreshState。我們将這個狀态傳遞給 SwipeRefresh,但如果需要,我們也可以訪問它的屬性 isRefreshing 和 isSwipeInProgress。在 SwipeRefresh 中,我們有一個标題、當前時間和項目列表。每行項目隻顯示一個圖像和數字。
SwipeRefresh 具有三個強制參數:
一些有趣的可選參數是:
對于指标參數,您可以創建自己的可組合項,但該庫為我們提供了 SwipeRefreshIndicator,這是我們可以使用的非常好的可組合項。
它需要兩個參數:
一些可選參數是:
還有更多參數,但不需要全部遍曆。如果您想了解更多信息,請務必在官方文檔中查看。
這就是 SwipeRefresh 的全部内容,現在讓我們實現占位符,這是來自 Accompanist 的另一個不錯的庫。
占位符
通常,項目的加載由某種加載微調器顯示。另一種顯示項目正在加載的方法是使用占位符。
Accompanist 創建了一個庫,為我們提供了用于顯示占位符的修飾符。實際上有兩個占位符庫。一個是基礎,另一個是材料。建議我們使用 Material,但可以随意使用您需要的任何東西。沒有太大區别,API 大多是等價的。在本博客中,我們使用的是 Material。所以,讓我們用這個命令導入它:
implementation "com.google.accompanist:accompanist-placeholder-material:0.25.1"
注意:檢查是否有此依賴項的更新版本。
在繼續 MainScreen 之前,讓我們快速編輯 MainViewModel。 添加 init 和 isLoading StateFlow。 此外,使用 20 個默認 RowItem 初始化項目。
private val _items = MutableStateFlow(List(size = 20) { RowItem() })
val items = _items.asStateFlow()
private val _isLoading = MutableStateFlow(true)
val isLoading = _isLoading.asStateFlow()
init {
viewModelScope.launch {
delay(2000)
_items.value = generateItems()
_isLoading.value = false
}
}
我們的 ViewModel 現在看起來像這樣:
class MainViewModel : ViewModel() {
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing = _isRefreshing.asStateFlow()
private val _currentTime = MutableStateFlow(Instant.now())
val currentTime = _currentTime.asStateFlow()
private val _items = MutableStateFlow(List(size = 20) { RowItem() })
val items = _items.asStateFlow()
private val _isLoading = MutableStateFlow(true)
val isLoading = _isLoading.asStateFlow()
init {
viewModelScope.launch {
delay(2000)
_items.value = generateItems()
_isLoading.value = false
}
}
fun refresh() = viewModelScope.launch {
_isRefreshing.update { true }
// Simulate API call
delay(2000)
_currentTime.value = Instant.now()
_items.value = generateItems()
_isRefreshing.update { false }
}
private fun generateItems(): List<RowItem> {
val list = mutableListOf<RowItem>()
for (i in 1 until 20) {
list.add(
RowItem(
rowImage = randomSampleImageUrl(),
number = Random.nextInt(1, 1000)
)
)
}
return list
}
private fun randomSampleImageUrl(
seed: Int = (0..100000).random(),
width: Int = 300,
height: Int = width,
): String {
return "https://picsum.photos/seed/$seed/$width/$height"
}
}
data class RowItem(
val rowImage: String = "",
val number: Int = -1
)
接下來是在我們的屏幕中收集 isLoading,然後将其用作我們的占位符。 我們正在向 Item 可組合項添加一個新參數 childModifier:Modifier。
Item(
rowItem = it,
childModifier = Modifier.placeholder(
visible = isLoading,
highlight = PlaceholderHighlight.fade(),
)
)
如您所見,該庫為占位符提供了一個修飾符。必需的參數是可見的:布爾值,它确定是否應顯示占位符或内容。如果 visible 為真,那麼将有一個占位符來填充應用它的可組合項的大小,而不是内容。
可選參數有:
我們的 MainScreen 現在看起來像這樣:
@Composable
fun MainScreen(
viewModel: MainViewModel = viewModel()
) {
val isRefreshing = viewModel.isRefreshing.collectAsState().value
val isLoading = viewModel.isLoading.collectAsState().value
val currentTime = viewModel.currentTime.collectAsState().value
val items = viewModel.items.collectAsState().value
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing = isRefreshing)
SwipeRefresh(
state = swipeRefreshState,
onRefresh = viewModel::refresh,
modifier = Modifier
.fillMaxSize()
.padding(
vertical = 32.dp,
horizontal = 16.dp
)
) {
LazyColumn {
item {
Text(
text = "Welcome to Swipe-to-Refresh!",
style = MaterialTheme.typography.h5,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = currentTime.toString(),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.End
)
Spacer(modifier = Modifier.height(8.dp))
}
items(items) {
Item(
rowItem = it,
childModifier = Modifier.placeholder(
visible = isLoading,
highlight = PlaceholderHighlight.fade(),
)
)
}
}
}
}
@Composable
fun Item(
rowItem: RowItem,
childModifier: Modifier = Modifier,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
elevation = 4.dp
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = rememberAsyncImagePainter(rowItem.rowImage),
contentDescription = rowItem.number.toString(),
modifier = childModifier.size(64.dp)
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = "Number: ${rowItem.number}",
modifier = childModifier.fillMaxWidth()
)
}
}
}
就這樣。 我希望你喜歡它。
關注七爪網,獲取更多APP/小程序/網站源碼資源!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!