下拉即可重整畫面

使用者可以在應用程式內容開頭向下拖曳,透過「下拉更新」元件重新整理資料。

API 介面

使用 PullToRefreshBox 可組合函式實作「下拉式重新整理」功能,做為可捲動內容的容器。下列重要參數可控制重新整理行為和外觀:

  • isRefreshing:布林值,表示重新整理動作是否正在進行中。
  • onRefresh:使用者啟動重新整理時執行的 lambda 函式。
  • indicator:自訂系統在「下拉更新」時繪製的指標。

基本範例

這個程式碼片段示範 PullToRefreshBox 的基本用法:

@Composable
fun PullToRefreshBasicSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

程式碼重點

  • PullToRefreshBox 會包裝 LazyColumn,顯示字串清單。
  • PullToRefreshBox 需要 isRefreshingonRefresh 參數。
  • PullToRefreshBox 區塊內的內容代表可捲動的內容。

結果

這部影片展示了上述程式碼的基本下拉式重新整理實作:

圖 1. 項目清單的基本「下拉即重新整理」實作方式。

進階範例:自訂指標顏色

@Composable
fun PullToRefreshCustomStyleSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            Indicator(
                modifier = Modifier.align(Alignment.TopCenter),
                isRefreshing = isRefreshing,
                containerColor = MaterialTheme.colorScheme.primaryContainer,
                color = MaterialTheme.colorScheme.onPrimaryContainer,
                state = state
            )
        },
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

程式碼重點

  • 指標顏色是透過 indicator 參數中的 containerColorcolor 屬性自訂。
  • rememberPullToRefreshState() 會管理重新整理動作的狀態。 您會搭配 indicator 參數使用這個狀態。

結果

這部影片顯示的「下拉更新」實作方式,會使用彩色指標:

圖 2. 採用自訂樣式的「下拉更新」實作方式。

進階範例:建立完全自訂的指標

您可以運用現有的可組合函式和動畫,建立複雜的自訂指標。以下程式碼片段示範如何在下拉式重新整理實作中建立完全自訂的指標:

@Composable
fun PullToRefreshCustomIndicatorSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            MyCustomIndicator(
                state = state,
                isRefreshing = isRefreshing,
                modifier = Modifier.align(Alignment.TopCenter)
            )
        }
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

// ...
@Composable
fun MyCustomIndicator(
    state: PullToRefreshState,
    isRefreshing: Boolean,
    modifier: Modifier = Modifier,
) {
    Box(
        modifier = modifier.pullToRefreshIndicator(
            state = state,
            isRefreshing = isRefreshing,
            containerColor = PullToRefreshDefaults.containerColor,
            threshold = PositionalThreshold
        ),
        contentAlignment = Alignment.Center
    ) {
        Crossfade(
            targetState = isRefreshing,
            animationSpec = tween(durationMillis = CROSSFADE_DURATION_MILLIS),
            modifier = Modifier.align(Alignment.Center)
        ) { refreshing ->
            if (refreshing) {
                CircularProgressIndicator(Modifier.size(SPINNER_SIZE))
            } else {
                val distanceFraction = { state.distanceFraction.coerceIn(0f, 1f) }
                Icon(
                    imageVector = Icons.Filled.CloudDownload,
                    contentDescription = "Refresh",
                    modifier = Modifier
                        .size(18.dp)
                        .graphicsLayer {
                            val progress = distanceFraction()
                            this.alpha = progress
                            this.scaleX = progress
                            this.scaleY = progress
                        }
                )
            }
        }
    }
}

程式碼重點

  • 上一個程式碼片段使用了程式庫提供的 Indicator。這個程式碼片段會建立名為 MyCustomIndicator 的自訂指標可組合項。在這個可組合函式中,pullToRefreshIndicator 修飾符會處理定位和觸發重新整理。
  • 如上一個程式碼片段所示,這個範例會擷取 PullToRefreshState 例項,因此您可以將相同例項傳遞至 PullToRefreshBoxpullToRefreshModifier
  • 這個範例使用 PullToRefreshDefaults 類別的容器顏色和位置門檻。這樣一來,您就能重複使用 Material 程式庫的預設行為和樣式,同時只自訂感興趣的元素。
  • MyCustomIndicator 會使用 Crossfade 在雲端圖示和 CircularProgressIndicator 之間轉換。使用者下拉時,雲端圖示會放大,並在開始重新整理動作時轉換為 CircularProgressIndicator
    • targetState 會使用 isRefreshing 判斷要顯示的狀態 (雲端圖示或圓形進度指標)。
    • animationSpec 會為轉場效果定義 tween 動畫,並指定 CROSSFADE_DURATION_MILLIS 的時間長度。
    • state.distanceFraction 代表使用者下拉的距離,範圍從 0f (未下拉) 到 1f (完全下拉)。
    • graphicsLayer 修飾符會修改比例和透明度。

結果

這部影片顯示上述程式碼中的自訂指標:

圖 3. 使用自訂指標實作「下拉式重新整理」功能。

其他資源