### Basic EasyRefresh Setup Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Demonstrates the fundamental setup of EasyRefresh with onRefresh and onLoad callbacks for a ListView. ```dart import 'package:easy_refresh/easy_refresh.dart'; EasyRefresh( onRefresh: () async { await Future.delayed(const Duration(seconds: 2)); }, onLoad: () async { await Future.delayed(const Duration(seconds: 2)); }, child: ListView( children: [/* items */], ), ) ``` -------------------------------- ### Basic EasyRefresh Implementation Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/example.md This snippet demonstrates a fundamental setup of EasyRefresh with ClassicHeader and ClassicFooter. It includes logic for handling refresh and load more operations, simulating network delays, and updating the item count of a ListView. Use this as a starting point for implementing pull-to-refresh and infinite scrolling. ```dart import 'package:flutter/material.dart'; import 'package:easy_refresh/easy_refresh.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( title: 'EasyRefresh', home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State createState() => _HomePageState(); } class _HomePageState extends State { int _count = 10; late EasyRefreshController _controller; @override void initState() { super.initState(); _controller = EasyRefreshController( controlFinishRefresh: true, controlFinishLoad: true, ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('EasyRefresh'), ), body: EasyRefresh( controller: _controller, header: const ClassicHeader(), footer: const ClassicFooter(), onRefresh: () async { await Future.delayed(const Duration(seconds: 4)); if (!mounted) { return; } setState(() { _count = 10; }); _controller.finishRefresh(); _controller.resetFooter(); }, onLoad: () async { await Future.delayed(const Duration(seconds: 4)); if (!mounted) { return; } setState(() { _count += 5; }); _controller.finishLoad( _count >= 20 ? IndicatorResult.noMore : IndicatorResult.success); }, child: ListView.builder( itemBuilder: (context, index) { return Card( child: Container( alignment: Alignment.center, height: 80, child: Text('${index + 1}'), ), ); }, itemCount: _count, ), ), ); } } ``` -------------------------------- ### Installation Rules for Executable and Data Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/CMakeLists.txt Configures installation paths for the main executable, ICU data file, and Flutter library. It ensures assets are re-copied on each build. ```cmake set(BUILD_BUNDLE_DIR "$") set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) ``` -------------------------------- ### Refresh on Start with EasyRefresh Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/usage-examples.md This example shows how to trigger a refresh automatically when the widget is first displayed. It uses the `refreshOnStart` property and a state flag to ensure the initial data load occurs only once. ```dart class RefreshOnStartPage extends StatefulWidget { @override State createState() => _RefreshOnStartPageState(); } class _RefreshOnStartPageState extends State { List items = []; bool isInitialized = false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Refresh on Start')), body: EasyRefresh( refreshOnStart: !isInitialized, onRefresh: _loadInitialData, onLoad: () async { /* load more */ }, child: isInitialized && items.isEmpty ? const Center(child: Text('No items loaded')) : ListView.builder( itemCount: items.length, itemBuilder: (context, index) => ListTile( title: Text(items[index]), ), ), ), ); } Future _loadInitialData() async { await Future.delayed(const Duration(seconds: 2)); setState(() { items = List.generate(20, (i) => 'Item ${i + 1}'); isInitialized = true; }); } } ``` -------------------------------- ### IndicatorStateListenable Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/types.md Example of initializing and using IndicatorStateListenable with ListenerHeader. Allows external listening to indicator state changes. ```dart final listenable = IndicatorStateListenable(); ListenerHeader( listenable: listenable, triggerOffset: 70, // Listen from elsewhere // listenable.addListener(() { /* ... */ }) ) ``` -------------------------------- ### ListenerHeader Usage Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/indicators.md Shows how to use ListenerHeader to monitor header state changes and display them elsewhere in the widget tree. ```dart final headerListenable = IndicatorStateListenable(); Column( children: [ EasyRefresh( header: ListenerHeader( listenable: headerListenable, triggerOffset: 70, ), onRefresh: () async { /* ... */ }, child: ListView(), ), // Listen from elsewhere ValueListenableBuilder( valueListenable: headerListenable, builder: (context, state, _) { if (state == null) return const SizedBox(); return Text('Header offset: ${state.offset}'); }, ), ], ) ``` -------------------------------- ### Installation Rule for AOT Library Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/CMakeLists.txt Installs the Ahead-Of-Time (AOT) compilation library on non-Debug builds (Profile and Release). ```cmake install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ``` -------------------------------- ### Load Only Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Implement this for scenarios requiring only pull-up data loading. It sets up EasyRefresh for loading more items and uses a NotRefreshHeader. ```dart EasyRefresh( onLoad: () async { /* load more data */ }, notRefreshHeader: const NotRefreshHeader(), child: ListView(), ) ``` -------------------------------- ### Pagination with EasyPaging Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/advanced-patterns.md Implement pagination using the `easy_paging` package. This example shows how to integrate `EasyPagingController` with `EasyRefresh` to manage data fetching and display. ```dart import 'package:easy_paging/easy_paging.dart'; class PaginatedPage extends StatefulWidget { @override State createState() => _PaginatedPageState(); } class _PaginatedPageState extends State { late final paging = EasyPagingController( onRefresh: () => _fetchPage(1), onLoadMore: () => _fetchPage(paging.pageNumber + 1), ); @override Widget build(BuildContext context) { return EasyRefresh( onRefresh: paging.onRefresh, onLoad: paging.onLoadMore, child: ListView.builder( itemCount: paging.list.length, itemBuilder: (context, index) { final item = paging.list[index]; return ListTile(title: Text(item.title)); }, ), ); } Future _fetchPage(int pageNum) async { final items = await api.fetchItems(pageNum); if (pageNum == 1) { paging.list = items; } else { paging.list.addAll(items); } if (items.length < pageSize) { paging.noMore(); } else { paging.success(); } } } ``` -------------------------------- ### Custom BuilderHeader Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/indicators.md Demonstrates creating a custom header using the BuilderHeader, allowing for fully customized UI based on indicator state. ```dart EasyRefresh( header: BuilderHeader( triggerOffset: 80, clamping: false, position: IndicatorPosition.above, builder: (context, state) { return Container( height: 80, color: Colors.blue, child: Center( child: Text(state.mode.toString()), ), ); }, ), onRefresh: () async { /* ... */ }, child: ListView(), ) ``` -------------------------------- ### ERScrollBehaviorBuilder Usage Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/types.md Example of providing a custom ScrollBehavior to EasyRefresh. ```dart EasyRefresh( scrollBehaviorBuilder: (physics) { return MyCustomScrollBehavior(physics); }, ) ``` -------------------------------- ### IndicatorBuilder Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/types.md Example of using an IndicatorBuilder to construct a custom indicator. This displays a CircularProgressIndicator when processing and the current offset. ```dart BuilderHeader( builder: (context, state) { return Column( children: [ if (state.mode == IndicatorMode.processing) const CircularProgressIndicator(), Text(state.offset.toStringAsFixed(1)), ], ); }, ) ``` -------------------------------- ### Project and CMake Version Setup Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/CMakeLists.txt Sets the minimum required CMake version and the project name. It also explicitly opts into modern CMake behaviors. ```cmake cmake_minimum_required(VERSION 3.14) project(example LANGUAGES CXX) set(BINARY_NAME "example") cmake_policy(VERSION 3.14...3.25) ``` -------------------------------- ### Minimal Custom Paging Implementation Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/packages/easy_paging/README.md A basic example of how to create a custom paging widget by extending EasyPaging and implementing its required methods for data handling and UI rendering. ```dart class CustomPaging extends EasyPaging, String> { const CustomPaging({super.key}); @override EasyPagingState, String, CustomPaging> createState() => _CustomPagingState(); } class _CustomPagingState extends EasyPagingState, String, CustomPaging> { @override int get count => data?.length ?? 0; @override String getItem(int index) => data![index]; @override int? page; @override int? total; @override int? totalPage; @override Widget buildItem(BuildContext context, int index, String item) { return ListTile(title: Text(item)); } @override Future onRefresh() async { setState(() { data = List.generate(10, (index) => 'Item $index'); total = 30; page = 1; }); } @override Future onLoad() async { final nextPage = page! + 1; setState(() { data!.addAll(List.generate(10, (index) => 'Item ${data!.length + index}')); page = nextPage; }); } } ``` -------------------------------- ### Basic Load More Operation Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of an onLoad callback that fetches more data and returns IndicatorResult.noMore if no items are returned, otherwise IndicatorResult.success. ```dart EasyRefresh( onLoad: () async { final items = await _fetchMore(); if (items.isEmpty) { return IndicatorResult.noMore; } return IndicatorResult.success; }, child: ListView(), ) ``` -------------------------------- ### ERChildBuilder Usage Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/types.md Example of using ERChildBuilder to create a ListView with provided scroll physics. ```dart EasyRefresh.builder( childBuilder: (context, physics) { return ListView( physics: physics, children: [/* items */], ); }, ) ``` -------------------------------- ### ClassicHeader Usage Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/built-in-styles.md Demonstrates how to integrate ClassicHeader into an EasyRefresh widget. Customizes trigger offset, background color, and text labels for pull-to-refresh actions. ```dart EasyRefresh( header: ClassicHeader( triggerOffset: 80, backgroundColor: Colors.white, dragText: 'Swipe down to refresh', armedText: 'Release to refresh', processingText: 'Loading...', showMessage: true, messageText: 'Updated at %T', ), onRefresh: () async { /* ... */ }, child: ListView(), ) ``` -------------------------------- ### Implement a Basic Custom Header Indicator Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/advanced-patterns.md Extend the Header class to create a fully custom indicator. This example shows a basic header with configurable color and size, displaying the current indicator mode and offset. ```dart class MyCustomHeader extends Header { final Color color; final double size; const MyCustomHeader({ this.color = Colors.blue, this.size = 50, super.triggerOffset = 80, super.clamping = false, super.position = IndicatorPosition.above, }); @override Widget build(BuildContext context, IndicatorState state) { return Container( height: size, color: color, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(state.mode.toString()), Text('${state.offset.toStringAsFixed(1)} px'), if (state.mode == IndicatorMode.processing) const CircularProgressIndicator(), ], ), ), ); } } // Use it EasyRefresh( header: MyCustomHeader(color: Colors.purple), onRefresh: () async { /* ... */ }, child: ListView(), ) ``` -------------------------------- ### HeaderLocator with CustomScrollView Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/indicators.md Illustrates using HeaderLocator.sliver within a CustomScrollView to position an EasyRefresh header. ```dart EasyRefresh( header: Header( position: IndicatorPosition.locator, ), onRefresh: () async { /* ... */ }, child: CustomScrollView( slivers: [ const HeaderLocator.sliver(), SliverAppBar(title: Text('Title')), SliverList( delegate: SliverChildBuilderDelegate( (context, index) => ListTile(title: Text('Item $index')), ), ), ], ), ) ``` -------------------------------- ### Example: Progressive Friction Factor Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/physics-and-behavior.md Demonstrates a custom friction factor that increases progressively as the user overscrolls. This provides a more resistant feel at maximum overscroll. ```dart final friction = (double overscrollFraction) { // Start at 0.5 friction, increase to 0.8 at max return 0.5 + (overscrollFraction * 0.3); }; EasyRefresh( frictionFactor: friction, child: ListView(), ) ``` -------------------------------- ### Implement a Custom Header with Animations Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/advanced-patterns.md Create a custom header indicator that animates based on the scroll offset. This example features a rotating, color-changing container. ```dart class AnimatedCustomHeader extends Header { const AnimatedCustomHeader({ super.triggerOffset = 80, super.clamping = false, }); @override Widget build(BuildContext context, IndicatorState state) { // Progress based on offset final progress = (state.offset / state.actualTriggerOffset) .clamp(0, 1) .toDouble(); return SizedBox( height: 80, child: Center( child: Transform.rotate( angle: progress * 2 * 3.14159, child: Container( width: 40, height: 40, decoration: BoxDecoration( shape: BoxShape.circle, color: Color.lerp(Colors.blue, Colors.red, progress), ), ), ), ), ); } } ``` -------------------------------- ### Basic Usage of SpaceHeader and SpaceFooter Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/packages/easy_refresh_space/README.md Integrate SpaceHeader and SpaceFooter into your EasyRefresh widget for pull-to-refresh and load-more functionality. This example shows a basic setup with a ListView. ```dart EasyRefresh( header: SpaceHeader(), footer: SpaceFooter(), onRefresh: () async {}, onLoad: () async {}, child: ListView(), ) ``` -------------------------------- ### Basic CMake Configuration Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Sets the minimum CMake version and defines the ephemeral directory for generated build files. ```cmake cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") ``` -------------------------------- ### Custom FrictionFactor Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/types.md Example of creating a custom FrictionFactor. This function returns a value between 0.5 and 0.7 based on the overscroll. ```dart FrictionFactor myFriction = (overscrollFraction) { return 0.5 + (overscrollFraction * 0.2); // Ranges 0.5 to 0.7 }; ``` -------------------------------- ### Companion Packages Import Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/README.md Import necessary packages for using companion features like easy_paging with EasyRefresh. ```dart import 'package:easy_paging/easy_paging.dart'; import 'package:easy_refresh/easy_refresh.dart'; ``` -------------------------------- ### Get EasyRefreshData from Context Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/api-reference.md Static method to retrieve EasyRefreshData using a BuildContext. ```dart static EasyRefreshData of(BuildContext context) { // Returns EasyRefreshData } ``` -------------------------------- ### Constructor Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/controller.md Initializes the EasyRefreshController with options to control finish operations. ```APIDOC ## Constructor EasyRefreshController ### Description Initializes the EasyRefreshController. Allows for external control over refresh and load completion states. ### Parameters #### Constructor Parameters - **controlFinishRefresh** (bool) - Optional - When true, requires manual calling of `finishRefresh()` to end the refresh state. - **controlFinishLoad** (bool) - Optional - When true, requires manual calling of `finishLoad()` to end the load state. ``` -------------------------------- ### Disable Load Operation Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of disabling the pull-up load operation by setting onLoad to null and using NotLoadFooter. ```dart // Refresh only (no load) EasyRefresh( onRefresh: () async { await _refreshData(); }, notLoadFooter: const NotLoadFooter(), child: ListView(), ) ``` -------------------------------- ### Disable Refresh Operation Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of disabling the pull-down refresh operation by setting onRefresh to null and using NotRefreshHeader. ```dart // Load only (no refresh) EasyRefresh( onLoad: () async { await _loadMore(); }, notRefreshHeader: const NotRefreshHeader(), child: ListView(), ) ``` -------------------------------- ### Define C++ Wrapper Plugin Sources Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Lists the C++ source files specific to plugin registration and prepends the wrapper root directory. ```cmake list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") ``` -------------------------------- ### Apply Standard Build Settings Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/runner/CMakeLists.txt Applies a standard set of build settings to the application target. This can be customized for applications requiring different build configurations. ```cmake # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) ``` -------------------------------- ### ERScrollPhysics applyTo Method Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/physics-and-behavior.md Applies this physics to a scroll view. This method is called internally by Flutter during scroll view setup. ```dart @override _ERScrollPhysics applyTo(ScrollPhysics? ancestor) ``` -------------------------------- ### Define C++ Wrapper Core Sources Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Lists the core C++ source files for the client wrapper and prepends the wrapper root directory. ```cmake list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") ``` -------------------------------- ### listenable Method Signature Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/notifier-and-state.md Get a ValueListenable for this notifier's state. This listenable emits IndicatorState whenever the state changes. ```dart ValueListenable listenable() ``` -------------------------------- ### Load with Controller and canLoadAfterNoMore: false Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of onLoad with a controller and canLoadAfterNoMore set to false. This prevents further load attempts after IndicatorResult.noMore is returned. ```dart final controller = EasyRefreshController(controlFinishLoad: true); EasyRefresh( controller: controller, canLoadAfterNoMore: false, onLoad: () async { try { final hasMore = await _loadMore(); if (hasMore) { controller.finishLoad(); } else { controller.finishLoad(result: IndicatorResult.noMore); } } catch (e) { controller.finishLoad(result: IndicatorResult.fail); } }, child: ListView(), ) ``` -------------------------------- ### IndicatorNotifier Lifecycle and State Listening Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/notifier-and-state.md Explains the lifecycle of IndicatorNotifier modes and how to listen to state changes using ValueListenable. ```APIDOC ## IndicatorNotifier Lifecycle ### Mode Transitions ``` inactive ↓ drag (user pulling) ↓ armed (past trigger offset) ↓ release → ready ↓ processing (task running) ↓ processed (task done, animation pending) ↓ done (animation complete) ↓ inactive ``` ### State Change Listening Listen to indicator state changes: ```dart final headerListenable = IndicatorStateListenable(); ListenerHeader( listenable: headerListenable, triggerOffset: 70, ) // Listen elsewhere headerListenable.addListener(() { final state = headerListenable.value; if (state != null) { print('Mode: ${state.mode}'); print('Offset: ${state.offset}'); } }); ``` Or use `ValueListenableBuilder`: ```dart final notifier = EasyRefresh.of(context).headerNotifier; ValueListenableBuilder( valueListenable: notifier.listenable(), builder: (context, state, _) { if (state == null) return const SizedBox(); return Text('Offset: ${state.offset.toStringAsFixed(1)}'); }, ) ``` ``` -------------------------------- ### Explicit Refresh Result Handling Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of onRefresh callback that explicitly returns IndicatorResult.success or IndicatorResult.fail based on the outcome of data fetching. ```dart EasyRefresh( onRefresh: () async { try { await _refreshData(); return IndicatorResult.success; // Explicit success } catch (e) { return IndicatorResult.fail; // Explicit failure } }, child: ListView(), ) ``` -------------------------------- ### EasyRefreshController Constructor Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/controller.md Initializes the EasyRefreshController. Use `controlFinishRefresh` or `controlFinishLoad` to manually manage completion states. ```dart EasyRefreshController({ bool controlFinishRefresh = false, bool controlFinishLoad = false, }) ``` -------------------------------- ### Main Library Import Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Imports all public classes and enums from the easy_refresh package, making them available for use in your application. ```dart import 'package:easy_refresh/easy_refresh.dart'; ``` -------------------------------- ### Automatic Refresh Completion Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of onRefresh callback that automatically completes as success after fetching data. No explicit return value is needed. ```dart EasyRefresh( onRefresh: () async { // Fetch new data await Future.delayed(const Duration(seconds: 2)); // Automatically completes as success }, child: ListView(), ) ``` -------------------------------- ### indicatorState Getter Signature Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/notifier-and-state.md Get the current indicator state snapshot. Returns a complete IndicatorState object representing the current status. ```dart IndicatorState get indicatorState ``` -------------------------------- ### Add Dependency Libraries and Include Directories Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/runner/CMakeLists.txt Specifies the libraries and include directories required for the build. This includes Flutter-specific libraries and system libraries like dwmapi.lib. ```cmake # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") ``` -------------------------------- ### Define Application Target and Source Files Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/runner/CMakeLists.txt Defines the main executable target for the Windows runner and lists all necessary source files, including C++ files, generated files, and resource files. ```cmake cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) ``` -------------------------------- ### Refresh Only Example Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Use this snippet when only pull-down refresh functionality is needed. It configures the EasyRefresh widget to perform a refresh operation and uses a NotLoadFooter. ```dart EasyRefresh( onRefresh: () async { /* load data */ }, notLoadFooter: const NotLoadFooter(), child: ListView(), ) ``` -------------------------------- ### Custom Header and Footer Indicators Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/easy_refresh.md Demonstrates how to replace the default header and footer indicators with custom ones like `ClassicHeader` and `MaterialFooter`. Requires importing the respective indicator classes. ```dart EasyRefresh( header: ClassicHeader( dragText: 'Pull to refresh', armedText: 'Release to refresh', ), footer: MaterialFooter(), onRefresh: () async { /* ... */ }, onLoad: () async { /* ... */ }, child: ListView(), ) ``` -------------------------------- ### Export Flutter Library and ICU Data Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Publishes the Flutter library path and ICU data file to the parent scope for the install step. ```cmake # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) ``` -------------------------------- ### Profile Build Mode Settings Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/CMakeLists.txt Configures linker and compiler flags for the Profile build mode by copying settings from the Release build mode. ```cmake set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") ``` -------------------------------- ### Project Configuration (pubspec.yaml) Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Defines the project name, version, description, and required SDK environments for Dart and Flutter. It also lists the project's dependencies. ```yaml name: easy_refresh version: 3.5.0 description: A flutter widget that provides pull-down refresh and pull-up load. environment: sdk: ">=3.5.0 <4.0.0" flutter: ">=3.10.0" dependencies: flutter: sdk: flutter path_drawing: ^1.0.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^6.0.0 flutter: uses-material-design: true ``` -------------------------------- ### Inspect EasyRefresh Indicator State Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Provides an example of how to access and log the current state of EasyRefresh indicators, such as offset and mode, using EasyRefresh.of(context). ```dart final data = EasyRefresh.of(context); debugPrint('Header offset: ${data.headerNotifier.offset}'); debugPrint('Header mode: ${data.headerNotifier.mode}'); ``` -------------------------------- ### Manual Control Usage Pattern Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/controller.md Demonstrates how to use `EasyRefreshController` for manual control of refresh and load operations within an `EasyRefresh` widget. Ensure `controlFinishRefresh` and `controlFinishLoad` are set to true. ```dart final controller = EasyRefreshController( controlFinishRefresh: true, controlFinishLoad: true, ); EasyRefresh( controller: controller, onRefresh: () async { try { await _refreshData(); controller.finishRefresh(); } catch (e) { controller.finishRefresh(result: IndicatorResult.fail); } }, onLoad: () async { try { final hasMore = await _loadMore(); controller.finishLoad( result: hasMore ? IndicatorResult.success : IndicatorResult.noMore, ); } catch (e) { controller.finishLoad(result: IndicatorResult.fail); } }, child: ListView(), ) ``` -------------------------------- ### Setting Default Footer Builder Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Configures the default footer indicator for all EasyRefresh widgets in the application. This example uses ClassicFooter with a specified trigger offset. ```dart EasyRefresh.defaultFooterBuilder = () => ClassicFooter( triggerOffset: 70, ); ``` -------------------------------- ### Basic Refresh and Load Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/easy_refresh.md Demonstrates the fundamental usage of EasyRefresh for fetching new data on refresh and more data on load. Requires `onRefresh` and `onLoad` callbacks. ```dart EasyRefresh( onRefresh: () async { // Fetch new data await Future.delayed(const Duration(seconds: 2)); }, onLoad: () async { // Fetch more data await Future.delayed(const Duration(seconds: 2)); }, child: ListView( children: [/* items */], ), ) ``` -------------------------------- ### Add Dependencies Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/packages/easy_refresh_halloween/README.md Add the necessary dependencies to your pubspec.yaml file to use the Halloween indicators. ```yaml dependencies: flutter_easyre_fresh: version easy_refresh_halloween: version ``` -------------------------------- ### Automatic Refresh on Start Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Configures EasyRefresh to automatically trigger a refresh operation when the widget is first built. Includes a custom header for initial loading state. ```dart EasyRefresh( refreshOnStart: true, refreshOnStartHeader: ClassicHeader( dragText: 'Initial loading...', ), onRefresh: () async { await _loadInitialData(); }, child: ListView(), ) ``` -------------------------------- ### Dispose EasyRefreshController Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/api-reference.md Best practice: Ensure EasyRefreshController is properly disposed of to prevent memory leaks. This example shows cleanup within a StatefulWidget's dispose method. ```dart class MyPage extends StatefulWidget { @override State createState() => _MyPageState(); } class _MyPageState extends State { late final controller = EasyRefreshController(); @override void dispose() { controller._state = null; // or similar cleanup super.dispose(); } @override Widget build(BuildContext context) { return EasyRefresh( controller: controller, // ... ); } } ``` -------------------------------- ### With Controller for Manual Finish Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/easy_refresh.md Illustrates using `EasyRefreshController` to manually control the finish state of refresh and load operations. Set `controlFinishRefresh` and `controlFinishLoad` to true. ```dart final controller = EasyRefreshController( controlFinishRefresh: true, controlFinishLoad: true, ); EasyRefresh( controller: controller, onRefresh: () async { // Load data controller.finishRefresh(); }, onLoad: () async { // Load more data controller.finishLoad(IndicatorResult.noMore); }, child: ListView(), ) ``` -------------------------------- ### Include Generated Configuration Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Includes the generated configuration file provided by the Flutter tool. ```cmake # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) ``` -------------------------------- ### Custom Error Handling in Callback Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Example of implementing custom error handling within the onRefresh callback using a try-catch block to log errors and return IndicatorResult.fail. ```dart EasyRefresh( onRefresh: () async { try { await _fetchData(); return IndicatorResult.success; } catch (e) { debugPrint('Refresh failed: $e'); return IndicatorResult.fail; } }, child: ListView(), ) ``` -------------------------------- ### Indicator Mode Transitions Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/notifier-and-state.md Illustrates the lifecycle of an indicator's mode, from inactive to done. Understanding these transitions is key to managing indicator behavior. ```text inactive ↓ drag (user pulling) ↓ armed (past trigger offset) ↓ release → ready ↓ processing (task running) ↓ processed (task done, animation pending) ↓ done (animation complete) ↓ inactive ``` -------------------------------- ### Setting Default Header Builder Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Configures the default header indicator for all EasyRefresh widgets in the application. This example uses MaterialHeader with specific trigger offset and clamping behavior. ```dart EasyRefresh.defaultHeaderBuilder = () => MaterialHeader( triggerOffset: 100, clamping: true, ); ``` -------------------------------- ### Add Dependencies Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/packages/easy_refresh_bubbles/README.md Add the necessary dependencies to your pubspec.yaml file to use EasyRefresh and the bubbles indicator. ```yaml dependencies: flutter_easyre_fresh: version easy_refresh_bubbles: version ``` -------------------------------- ### Configure Nested ScrollView with EasyRefresh Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/advanced-patterns.md Enable NestedScrollView handling for complex nested scroll scenarios using `isNested: true`. This example configures a MaterialHeader and integrates with NestedScrollView's slivers. ```dart EasyRefresh.builder( header: MaterialHeader( clamping: true, position: IndicatorPosition.locator, ), onRefresh: () async { /* ... */ }, onLoad: () async { /* ... */ }, isNested: true, // Enable NestedScrollView handling (v3.4.0+) childBuilder: (context, physics) { return NestedScrollView( physics: physics, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ const HeaderLocator.sliver(clearExtent: false), SliverAppBar( floating: true, snap: true, title: const Text('Title'), ), ]; }, body: ListView( physics: physics, children: [ const FooterLocator.sliver(), for (int i = 0; i < 20; i++) ListTile(title: Text('Item $i')), ], ), ); }, ) ``` -------------------------------- ### Define Project Build Directory and AOT Library Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Sets the project's build directory and the path to the Ahead-Of-Time (AOT) compiled library. ```cmake set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) ``` -------------------------------- ### Setting Global Default Styles Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/easy_refresh.md Shows how to set application-wide default header and footer builders using static properties. This affects all `EasyRefresh` instances unless overridden. ```dart // Set application-wide defaults EasyRefresh.defaultHeaderBuilder = () => ClassicHeader(); EasyRefresh.defaultFooterBuilder = () => ClassicFooter(); ``` -------------------------------- ### Custom Header Indicator Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/usage-examples.md Build a completely custom refresh header using a builder function. This example shows a rotating icon and dynamic text based on the indicator's state and progress. ```dart class CustomHeaderPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Custom Header')), body: EasyRefresh( header: BuilderHeader( triggerOffset: 80, clamping: false, position: IndicatorPosition.above, builder: (context, state) { // Compute progress (0 to 1) final progress = (state.offset / state.actualTriggerOffset) .clamp(0, 1) .toDouble(); return SizedBox( height: 80, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Rotating icon Transform.rotate( angle: progress * 6.28, child: Icon( Icons.refresh, size: 30, color: Color.lerp(Colors.grey, Colors.blue, progress), ), ), const SizedBox(height: 8), // State text Text( _getModeText(state.mode), style: const TextStyle(fontSize: 12), ), ], ), ), ); }, ), onRefresh: () async { await Future.delayed(const Duration(seconds: 2)); }, child: ListView.builder( itemCount: 20, itemBuilder: (context, index) => ListTile( title: Text('Item $index'), ), ), ), ); } String _getModeText(IndicatorMode mode) { switch (mode) { case IndicatorMode.inactive: return 'Pull down'; case IndicatorMode.drag: return 'Pulling...'; case IndicatorMode.armed: return 'Release to refresh'; case IndicatorMode.ready: return 'Releasing...'; case IndicatorMode.processing: return 'Refreshing...'; case IndicatorMode.processed: return 'Done!'; default: return ''; } } } ``` -------------------------------- ### Handle Refresh and Load Errors Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/usage-examples.md Implement error handling for refresh and load operations using EasyRefreshController. This example shows how to catch exceptions, display error messages, and signal failure to the refresh/load indicators. ```dart class ErrorHandlingPage extends StatefulWidget { @override State createState() => _ErrorHandlingPageState(); } class _ErrorHandlingPageState extends State { late final controller = EasyRefreshController( controlFinishRefresh: true, controlFinishLoad: true, ); List items = []; String? error; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Error Handling')), body: Column( children: [ if (error != null) Container( color: Colors.red.shade100, padding: const EdgeInsets.all(8), child: Row( children: [ Expanded(child: Text(error!)), IconButton( icon: const Icon(Icons.close), onPressed: () => setState(() => error = null), ), ], ), ), Expanded( child: EasyRefresh( controller: controller, onRefresh: _handleRefresh, onLoad: _handleLoad, child: items.isEmpty ? const Center(child: Text('No items')) : ListView.builder( itemCount: items.length, itemBuilder: (context, index) => ListTile( title: Text(items[index]), ), ), ), ), ], ), ); } Future _handleRefresh() async { try { final newItems = await _fetchDataWithError(); setState(() { items = newItems; error = null; }); controller.finishRefresh(); } catch (e) { setState(() => error = 'Refresh failed: $e'); controller.finishRefresh(result: IndicatorResult.fail); } } Future _handleLoad() async { try { final moreItems = await _fetchDataWithError(); setState(() { items.addAll(moreItems); error = null; }); controller.finishLoad(); } catch (e) { setState(() => error = 'Load failed: $e'); controller.finishLoad(result: IndicatorResult.fail); } } Future> _fetchDataWithError() async { await Future.delayed(const Duration(seconds: 2)); // Simulate random error if (DateTime.now().millisecond % 3 == 0) { throw Exception('Network error'); } return List.generate(10, (i) => 'Item ${items.length + i + 1}'); } } ``` -------------------------------- ### Load with Controller for Manual Completion Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/callback-patterns.md Demonstrates using EasyRefreshController with controlFinishLoad set to true. The onLoad callback manually calls controller.finishLoad() or controller.finishLoad(result: IndicatorResult.noMore/fail). ```dart final controller = EasyRefreshController(controlFinishLoad: true); EasyRefresh( controller: controller, onLoad: () async { try { final hasMore = await _loadMoreData(); if (hasMore) { controller.finishLoad(); } else { controller.finishLoad(result: IndicatorResult.noMore); } } catch (e) { controller.finishLoad(result: IndicatorResult.fail); } }, child: ListView(), ) ``` -------------------------------- ### Indicator State Listening and Positioning Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Explains `ListenerHeader`/`ListenerFooter` for reacting to indicator state changes and `HeaderLocator`/`FooterLocator` for positioning indicators within the scroll view. ```APIDOC ## Indicator State Listening and Positioning ### `ListenerHeader` / `ListenerFooter` Indicators that provide callbacks or mechanisms to listen to and react to the state changes of the refresh or load indicators. ### `HeaderLocator` / `FooterLocator` Components used to precisely position header and footer indicators within a scrollable area, often used in conjunction with `NestedScrollView`. ``` -------------------------------- ### Error Handling and Retry Logic with EasyRefreshController Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/advanced-patterns.md Implement robust error handling for refresh and load more operations. This example uses `EasyRefreshController` to control the finish state of indicators and provides a mechanism for retrying failed operations. ```dart class ErrorHandlingPage extends StatefulWidget { @override State createState() => _ErrorHandlingPageState(); } class _ErrorHandlingPageState extends State { final controller = EasyRefreshController( controlFinishRefresh: true, controlFinishLoad: true, ); @override Widget build(BuildContext context) { return EasyRefresh( controller: controller, onRefresh: _handleRefresh, onLoad: _handleLoad, child: ListView(), ); } Future _handleRefresh() async { try { await _fetchData(); controller.finishRefresh(); } catch (e) { controller.finishRefresh(result: IndicatorResult.fail); _showErrorSnackbar('Failed to refresh: $e'); } } Future _handleLoad() async { try { final hasMore = await _fetchMore(); if (hasMore) { controller.finishLoad(); } else { controller.finishLoad(result: IndicatorResult.noMore); } } catch (e) { controller.finishLoad(result: IndicatorResult.fail); _showErrorSnackbar('Failed to load: $e'); } } void _showErrorSnackbar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message)), ); } Future _fetchData() async { /* ... */ } Future _fetchMore() async { /* ... */ } } ``` -------------------------------- ### Build Flutter Wrapper Plugin Library Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Creates a static library for the Flutter C++ wrapper used by plugins. It links against the Flutter library and sets visibility and include directories. ```cmake # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) ``` -------------------------------- ### Set Wrapper Root Directory Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Defines the root directory for the C++ client wrapper sources. ```cmake set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") ``` -------------------------------- ### EasyRefresh with Custom Indicators Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Shows how to apply custom styling to EasyRefresh using MaterialHeader and ClassicFooter, with specified trigger offsets. ```dart EasyRefresh( header: MaterialHeader( color: Colors.blue, triggerOffset: 100, ), footer: ClassicFooter( triggerOffset: 70, ), onRefresh: () async { /* ... */ }, onLoad: () async { /* ... */ }, child: ListView(), ) ``` -------------------------------- ### Localizing ClassicHeader Texts Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Demonstrates how to localize the text displayed by the ClassicHeader. It shows passing localized strings for drag, armed, and ready states using a hypothetical AppLocalizations object. ```dart ClassicHeader( dragText: AppLocalizations.of(context)?.pullToRefresh ?? 'Pull to refresh', armedText: AppLocalizations.of(context)?.releaseToRefresh ?? 'Release to refresh', // ... other texts ) ``` -------------------------------- ### Indicator Base Classes and Builders Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/README.md Describes the abstract base classes for `Header` and `Footer` indicators, and provides builder-based classes for creating custom indicators. ```APIDOC ## Indicator Base Classes and Builders ### `Header` / `Footer` Abstract base classes defining the contract for refresh and load indicators. ### `BuilderHeader` / `BuilderFooter` Indicator classes that allow for the creation of custom indicators using a builder function, providing more flexibility in UI design. ``` -------------------------------- ### Animation Triggers - Trigger When Reach Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/notifier-and-state.md Demonstrates how to configure an indicator to trigger immediately when the trigger offset is reached, without requiring a release. ```APIDOC ## Animation Triggers ### Trigger When Reach Trigger immediately when reaching trigger offset (no release required). ```dart EasyRefresh( header: ClassicHeader( triggerOffset: 70, triggerWhenReach: true, // Trigger on reach ), onRefresh: () async { /* ... */ }, child: ListView(), ) ``` ``` -------------------------------- ### Define C++ Wrapper App Sources Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/example/windows/flutter/CMakeLists.txt Lists the C++ source files for the Flutter application runner and prepends the wrapper root directory. ```cmake list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") ``` -------------------------------- ### Build Release Web App Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/configuration.md Command to build a release version of a web application using Flutter. This command optimizes the build for production. ```bash flutter build web --release ``` -------------------------------- ### BezierHeader / BezierFooter Source: https://github.com/xuelongqy/flutter_easy_refresh/blob/v3/_autodocs/api-reference.md Configuration options for the BezierHeader and BezierFooter indicators. Supports customization of trigger offsets, clamping, ball visibility, spin behavior, and colors. ```APIDOC ## BezierHeader / BezierFooter ### Description Configuration for BezierHeader and BezierFooter. ### Properties - `triggerOffset` (double) - Default: 100 - `clamping` (bool) - Default: false - `showBalls` (bool) - Whether to show balls, Default: true - `spinInCenter` (bool) - Whether to spin in the center, Default: true - `onlySpin` (bool) - Whether to only spin, Default: false - `spinWidget` (Widget?) - Widget to use for spinning - `noMoreWidget` (Widget?) - Widget to display when no more items - `foregroundColor` (Color?) - Foreground color - `backgroundColor` (Color?) - Background color ```