七爪是什麼(七爪源碼JetpackCompose)
2023-10-07 04:11:27 2
關於如何在加載項目時實現滑動刷新功能以及佔位符的簡短指南
今天,許多應用程式都有需要在某個時候刷新的數據。 您可以在一段時間後刷新數據或使用套接字來始終擁有最新的數據,但是如果您想要允許用戶開始刷新數據的功能怎麼辦?
這可以通過一個按鈕來完成,但在某些情況下,更好的用戶體驗將是滑動刷新。 今天,我們將使用 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 { val list = mutableListOf 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 個項目的列表。
現在,讓我們創建我們的屏幕:
@Composablefun 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 ) } } } }}@Composablefun 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 具有三個強制參數:
state: SwipeRefreshState — 可以提升以控制和觀察 SwipeRefresh 更改的狀態對象onRefresh: -> Unit — 完成滑動刷新手勢時調用的 Lambdacontent: @Composable -> Unit — 包含可組合滾動的內容一些有趣的可選參數是:
swipeEnabled: Boolean - 布局是否應該對滑動手勢做出反應refreshTriggerDistance: Dp — 觸發刷新的最小滑動距離indicatorAlignment: Alignment — 指標的對齊方式。默認為 Alignment.TopCenterindicatorPadding: PaddingValues — 指標的內容填充,如果需要可以插入指標indicator:@Composable (state: SwipeRefreshState, refreshTrigger: Dp) — 表示當前狀態的指標。默認情況下,這將使用 SwipeRefreshIndicator對於指標參數,您可以創建自己的可組合項,但該庫為我們提供了 SwipeRefreshIndicator,這是我們可以使用的非常好的可組合項。
它需要兩個參數:
state: SwipeRefreshState — 傳遞到 SwipeRefresh 指示器塊的 SwipeRefreshStaterefreshTriggerDistance: Dp — 觸發刷新的最小滑動距離一些可選參數是:
fade: Boolean — 箭頭在滾動時是否應該淡入/淡出,默認為 truescale: Boolean — 指示器在滾動時是否應按比例放大/縮小,默認為 falsearrowEnabled: Boolean — 是否應在指標上繪製箭頭,默認為 truebackgroundColor: Color — 指示器背景表面的顏色還有更多參數,但不需要全部遍歷。如果您想了解更多信息,請務必在官方文檔中查看。
這就是 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.asStateFlowprivate val _isLoading = MutableStateFlow(true)val isLoading = _isLoading.asStateFlowinit { 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 { val list = mutableListOf 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 為真,那麼將有一個佔位符來填充應用它的可組合項的大小,而不是內容。
可選參數有:
color: Color — 用於繪製佔位符 UI 的顏色。如果提供了 Color.Unspecified,則佔位符將使用 PlaceholderDefaults.colorshape: Shape — 佔位符的所需形狀。如果提供 null,佔位符將使用 MaterialTheme.shapes 中設置的小形狀highlight: PlaceholderHighlight — 可選的高亮動畫。有兩個預先創建的佔位符動畫,淡入淡出和微光placeholderFadeTransitionSpec: @Composable Transition.Segment. -> FiniteAnimationSpec — 將佔位符淡入/淡出屏幕時使用的轉換規範。為過渡定義的布爾參數可見contentFadeTransitionSpec: @Composable Transition.Segment. -> FiniteAnimationSpec — 將內容淡入/淡出屏幕時使用的轉換規範。為過渡定義的布爾參數可見我們的 MainScreen 現在看起來像這樣:
@Composablefun 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, ) ) } } }}@Composablefun 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/小程序/網站源碼資源!
,