下拉即可重整畫面

透過「拉動即可刷新」元件,使用者可以在應用程式內容的開頭向下拖曳,藉此刷新資料。

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:使用自訂指標的下拉刷新實作方式。

其他資源