CupertinoSliverRefreshControl

实现iOS风格下拉刷新内容控件的sliver小部件

CupertinoSliverRefreshControl是Flutter中iOS风格(Cupertino)的下拉刷新组件,用于在CustomScrollView或者NestedScrollView中实现类似iOS原生APP的下拉刷新效果。

核心特性

  • iOS风格: 带有弹性动画和圆形进度指示器
  • 基于Sliver: 必须配合CustomScrollView使用
  • 异步刷新: 通过Future处理刷新逻辑

当作为滚动视图中的第一个Sliver插入,或置于其他仍允许在该Sliver前方产生滚动越界的Sliver(例如CupertinoSliverNavigationBar)之后时,此组件将:

  • 通过传入的builder允许用户在越界滚动区域中进行绘制
  • 当越界滚动距离超过refreshTriggerPullDistance时,触发提供的onRefresh函数
  • onRefresh返回的Future执行期间,继续保留refreshIndicatorExtent大小的空间,供builder持续绘制
  • 一旦onRefreshFuture完成,该组件将滚动消失

builder函数在调用时会收到当前的RefreshIndicatorMode状态,但在RefreshIndicatorMode.inactive状态下(此时没有可用空间,也无需构建内容)不会被调用。除此之外,当可用空间因越界滚动、onRefresh任务完成后Sliver滚动消失等情况发生变化时,builder函数将持续被调用。

ps: 在上一次刷新完成且指示器Sliver至少回缩90%之前,无法触发新的刷新。

该组件仅可用于支持越界滚动的向下滚动垂直列表。换言之,在默认使用ClampingScrollPhysics(Android平台默认)的可滚动组件中无法触发刷新。若要在Android上启用越界滚动,可以使用支持越界滚动的物理效果,例如BouncingScrollPhysics。可以通过以下方式实现:

  • 在构建可滚动组件时提供BouncingScrollPhysics(可与AlwaysScrollableScrollPhysics结合使用)
  • 在可滚动组件上方插入一个使用BouncingScrollPhysicsScrollConfiguration
  • 使用CupertinoApp,它会无视平台始终使用带有BouncingScrollPhysicsScrollConfiguration

在典型应用中,该组件应插入在应用栏Sliver(如CupertinoSliverNavigationBar)和主滚动内容的Sliver之间。

代码示例

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const CupertinoApp(
      title: 'CupertinoSliverRefreshControl Demo',
      home: RefreshPage(),
    );
  }
}

class RefreshPage extends StatefulWidget {
  const RefreshPage({super.key});

  
  State<RefreshPage> createState() => _RefreshPageState();
}

class _RefreshPageState extends State<RefreshPage> {
  List<String> items = List.generate(20, (index) => 'Item ${index + 1}');

  // 模拟异步刷新
  Future<void> _handleRefresh() async {
    await Future.delayed(const Duration(seconds: 2)); // 模拟网络请求
    setState(() {
      items = List.generate(20, (index) => 'Refreshed Item ${index + 1}');
    });
  }

  
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text('下拉刷新'),
      ),
      child: CustomScrollView(
        slivers: [
          CupertinoSliverRefreshControl(
            onRefresh: _handleRefresh,
            // 可选:自定义刷新指示器颜色
            // refreshIndicatorExtent: 100,
            // builder: (context, refreshState, pulledExtent, ...) { ... },
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => CupertinoListTile(
                title: Text(items[index]),
              ),
              childCount: items.length,
            ),
          ),
        ],
      ),
    );
  }
}

自定义刷新指示器

CupertinoSliverRefreshControl(
  onRefresh: _handleRefresh,
  builder: (
    BuildContext context,
    RefreshIndicatorMode refreshState,
    double pulledExtent,
    double refreshTriggerPullDistance,
    double refreshIndicatorExtent,
  ) {
    return Center(
      child: CupertinoActivityIndicator(
        animating: refreshState == RefreshIndicatorMode.refresh,
      ),
    );
  },
)

注意事项

  1. 必须配合CustomScrollView: 不能直接在ListView中使用
  2. iOS风格限制: 在Android上可能看起来不协调,建议使用RefreshIndicator(Material风格)
  3. 异步逻辑: 确保onRefresh返回的Future正确完成,否则会一直显示加载动画

进阶功能

  • 结合NestedScrollView: 实现嵌套滚动刷新(如TabBar+列表)
  • 动态控制刷新: 通过GlobalKey或状态管理触发刷新

构造函数

CupertinoSliverRefreshControl.new({
  Key? key, 
  double refreshTriggerPullDistance = _defaultRefreshTriggerPullDistance, 
  double refreshIndicatorExtent = _defaultRefreshIndicatorExtent, 
  RefreshControlIndicatorBuilder? builder = buildRefreshIndicator, 
  RefreshCallback? onRefresh
})

属性

参数名类型说明
onRefreshFuture<void> Function()必填,触发刷新时调用的异步函数。
refreshTriggerPullDistancedouble触发刷新的下拉距离(默认 100.0)。
refreshIndicatorExtentdouble刷新指示器的固定高度(默认 60.0)。
builderWidget Function(...)自定义刷新指示器的 UI(可选)。