RefreshTrigger#
스크롤 가능한 콘텐츠를 아래로 당겨서 새로고침을 트리거하는 컴포넌트입니다. iOS와 Android 스타일의 당겨서 새로고침 패턴을 구현합니다.
Live Preview#
Web
Pull to refresh
Pull to refresh
Flutter
Loading Flutter...
RefreshTrigger(
stage: TriggerStage.idle,
child: text('Pull to refresh'),
)
// RefreshTrigger requires scroll context
RefreshTrigger(
onRefresh: handleRefresh,
child: Text('Pull to refresh'),
)
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 소셜 피드, 뉴스 목록처럼 최신 데이터를 수동으로 불러와야 할 때
- 모바일 앱에서 네이티브 pull-to-refresh 패턴을 구현할 때
- 스크롤 가능한 영역의 내용을 사용자가 직접 갱신할 수 있어야 할 때
대신 다른 컴포넌트를 사용하세요:
Loading: 자동 새로고침 또는 페이지 로딩 중 표시에Progress: 작업 진행 상태를 퍼센트로 표시할 때
기본 사용법 (Basic Usage)#
// 기본 당겨서 새로고침
RefreshTrigger(
onRefresh: handleRefresh,
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => ListTile(
title: Text(_items[index]),
),
),
)
// 변위 및 색상 커스터마이징
RefreshTrigger(
onRefresh: handleRefresh,
displacement: 60.0,
color: Colors.blue,
child: SingleChildScrollView(
child: Column(
children: _buildContentList(),
),
),
)
RefreshTrigger(
onRefresh: handleRefresh,
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => ListTile(
title: Text(_items[index]),
),
),
)
RefreshTrigger(
onRefresh: handleRefresh,
displacement: 60.0,
color: Colors.blue,
child: ContentList(items: _items),
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
onRefresh |
Future<void> Function() |
필수 | 새로고침 트리거 시 호출되는 비동기 핸들러 |
child | Widget | 필수 | 새로고침 대상 스크롤 가능한 위젯 |
displacement |
double |
40.0 |
인디케이터가 표시되는 거리(px) |
color |
Color? |
null |
새로고침 인디케이터 색상 |
변형 (Variants)#
기본 (Default)#
시스템 기본 새로고침 인디케이터를 사용합니다.
RefreshTrigger(
onRefresh: handleRefresh,
child: ListView(children: _buildItems()),
)
커스텀 색상#
브랜드 색상에 맞게 인디케이터 색상을 변경합니다.
RefreshTrigger(
onRefresh: handleRefresh,
color: Theme.of(context).colorScheme.primary,
child: ListView(children: _buildItems()),
)
넓은 변위#
인디케이터가 더 많이 당겨져야 새로고침이 트리거됩니다.
RefreshTrigger(
onRefresh: handleRefresh,
displacement: 80.0,
child: ListView(children: _buildItems()),
)
동작 스펙 (Behavior)#
인터랙션#
- 당기기: 스크롤 최상단에서 아래로 당기면 인디케이터 표시
- 충분히 당기기:
displacement이상 당기면 새로고침 트리거 표시 - 해제: 당기기를 놓으면
onRefresh()호출, 완료까지 인디케이터 표시 - 중단:
displacement미만에서 놓으면 복귀
상태 전환#
idle→dragging: 최상단에서 아래로 드래그 시작dragging→ready: displacement 초과ready→refreshing: 드래그 해제 후 onRefresh 실행refreshing→idle: Future 완료 후
애니메이션#
- 인디케이터 등장: 드래그 거리에 비례한 회전 애니메이션
- 새로고침 중: 무한 회전 스피너
- 복귀: 스프링 효과 300ms
사용 가이드라인 (Usage Guidelines)#
✅ Do#
onRefresh를 async/await로 올바르게 구현
Future<void> handleRefresh() async {
final newData = await fetchLatestData();
setState(() {
_items = newData;
});
// Future가 완료되면 인디케이터 자동 숨김
}
CouiRefreshTrigger(
onRefresh: handleRefresh,
child: itemList,
)
onRefresh가 올바르게 완료되어야 인디케이터가 자동으로 숨겨진다.
❌ Don't#
스크롤할 수 없는 위젯에 RefreshTrigger 사용
// ❌ 스크롤 불가능한 위젯에 사용
CouiRefreshTrigger(
onRefresh: handleRefresh,
child: Container(
child: Text('스크롤 없는 콘텐츠'),
),
)
스크롤 가능한 위젯이 없으면 pull 제스처가 작동하지 않는다.
✅ Do#
브랜드 색상으로 인디케이터 색상 지정
CouiRefreshTrigger(
onRefresh: handleRefresh,
color: Theme.of(context).colorScheme.primary,
child: feedList,
)
브랜드 색상의 인디케이터는 앱의 일관된 시각 언어를 유지한다.
❌ Don't#
새로고침 중에도 UI가 완전히 차단되지 않도록 주의
// ❌ 새로고침 중 전체 화면을 가리는 로딩 오버레이
CouiRefreshTrigger(
onRefresh: () async {
showFullScreenLoader(); // 중복 로딩 표시
await fetchData();
hideFullScreenLoader();
},
child: feedList,
)
RefreshTrigger 자체가 로딩 인디케이터를 표시하므로 별도 전체 화면 로딩은 중복이다.
✅ Do#
새로고침 완료 후 명확한 피드백을 제공하세요.
CouiRefreshTrigger(
onRefresh: () async {
await dataRepository.refresh();
// 새로고침 완료 후 스낵바 또는 업데이트 시간 표시
showRefreshCompleted();
},
child: ContentList(),
)
새로고침이 완료되면 사용자가 데이터가 업데이트되었음을 인식할 수 있도록 명확한 피드백을 제공하세요.
❌ Don't#
새로고침 중 추가 인터랙션을 허용하지 마세요.
// ❌ 새로고침 중 버튼 클릭 가능
CouiRefreshTrigger(
onRefresh: handleRefresh,
child: Column(
children: [
ContentList(),
CouiButton(
onPressed: handleLoadMore, // 새로고침 중에도 활성화됨
child: Text('더 보기'),
),
],
),
)
새로고침 중에는 다른 데이터 요청을 막아야 데이터 충돌이나 중복 요청을 방지할 수 있습니다.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
| 해당 없음 | 제스처 기반 컴포넌트; 키보드 대안은 새로고침 버튼으로 제공 권장 |
스크린 리더#
- Flutter: 새로고침 상태 변경 시
SemanticsService.announce("새로고침 완료")호출 - Web:
aria-live="polite"영역에 새로고침 상태 메시지 업데이트
터치 타겟#
- 제스처 기반 컴포넌트로 별도 터치 타겟 없음
- 접근성을 위해 화면 상단에 새로고침 버튼을 추가로 제공 권장
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | CouiRefreshTrigger | RefreshTrigger |
| 인디케이터 | CircularProgressIndicator | CSS 스피너 또는 커스텀 |
| 제스처 감지 | RefreshIndicator 래핑 | Touch/Pointer Events |
| 오버스크롤 | 플랫폼 기본 오버스크롤 | overscroll-behavior CSS |
관련 컴포넌트 (Related Components)#
조합 예제#
// 피드 화면에 RefreshTrigger 적용
Scaffold(
appBar: AppBar(
title: const Text('피드'),
actions: [
// 키보드 접근성을 위한 새로고침 버튼
IconButton(
onPressed: handleManualRefresh,
icon: const Icon(Icons.refresh),
tooltip: '새로고침',
),
],
),
body: CouiRefreshTrigger(
onRefresh: handleRefresh,
color: Theme.of(context).colorScheme.primary,
child: ListView.builder(
itemCount: feedItems.length,
itemBuilder: (context, index) => FeedCard(item: feedItems[index]),
),
),
)