Skip to content

Commit 87a1581

Browse files
authored
Merge pull request #17 from gonuit/1.0.0
### Changes: - Stable nullsafety release. - **BREAKING**: Removed `prevState` from `IndicatorController` class. Because flutter only marks the widget that it is ready for rebuild, it is possible that the controller state will change more than once during a single frame what causes one or more steps to be skipped. To still use `prevState` and `didChangeState` method, you can use `IndicatorStateHelper`. Take a look at `check_mark_indicator.dart` or `warp_indicator.dart` for example usage. - Added `IndicatorStateHelper` class. - Added `IndicatorController` unit tests. - Added warp indicator example. - Added `stopDrag` method to the `IndicatorController` class. It allows you to stop current user drag. Resolves #15, #16
2 parents 67438d4 + 6da4408 commit 87a1581

19 files changed

+1047
-83
lines changed

.github/workflows/test.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Tests
2+
on: pull_request
3+
4+
jobs:
5+
checks:
6+
name: Analyzer and unit tests
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v2
10+
- uses: subosito/flutter-action@v1.4.0
11+
- name: Getting packages
12+
run: flutter pub get
13+
- name: analyzis
14+
run: flutter analyze .
15+
- name: tests
16+
run: flutter test

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,6 @@ build/
7171
!**/ios/**/default.pbxuser
7272
!**/ios/**/default.perspectivev3
7373
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74+
75+
# Flutter version manager
76+
.fvm

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
## 1.0.0-nullsafety.0
2-
1+
## 1.0.0
2+
- Stable nullsafety release.
33
- **BREAKING**: opt into null safety
44
- Dart SDK constraints: >=2.12.0-0 <3.0.0
5+
- **BREAKING**: Removed `prevState` from `IndicatorController` class.
6+
Because flutter only marks the widget that it is ready for rebuild, it is possible that the controller state will change more than once during a single frame what causes one or more steps to be skipped. To still use `prevState` and `didChangeState` method, you can use `IndicatorStateHelper`. Take a look at `check_mark_indicator.dart` or `warp_indicator.dart` for example usage.
7+
- Added `IndicatorStateHelper` class.
8+
- Added `IndicatorController` unit tests.
9+
- Added warp indicator example.
10+
- Added `stopDrag` method to the `IndicatorController` class. It allows you to stop current user drag.
511

612
## 0.9.0
713

README.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
# Flutter Custom Refresh Indicator
22

3+
[![Tests](https://github.com/gonuit/flutter-custom-refresh-indicator/actions/workflows/test.yml/badge.svg)](https://github.com/gonuit/flutter-custom-refresh-indicator/actions/workflows/test.yml)
4+
35
This package provides `CustomRefreshIndicator` widget that make it easy to implement your own custom refresh indicator. It listens for scroll events from scroll widget passed to child argument and parsing it to data easy for custom refresh indicator implementation. Indicator data is provided by IndicatorController (third argument of builder method). Long story short... thats it!
46

57
If there is something that can be improved, fixed or you just have some great idea feel free to open github issue [HERE](https://github.com/gonuit/flutter-custom-refresh-indicator/issues) or open a pull request [HERE](https://github.com/gonuit/flutter-custom-refresh-indicator/pulls).
68

79
If you implemented your own custom refresh indicator with this library and you want it to be mentioned here or provided as an example to the eample app, just open a pull request [HERE](https://github.com/gonuit/flutter-custom-refresh-indicator/pulls).
810

911
### Table of Contents
12+
1013
- [Flutter Custom Refresh Indicator](#flutter-custom-refresh-indicator)
11-
- [Table of Contents](#table-of-contents)
14+
- [Table of Contents](#table-of-contents)
1215
- [QUICK START](#quick-start)
1316
- [Examples](#examples)
1417
- [Documentation](#documentation)
@@ -68,17 +71,14 @@ Almost all of these examples are available in the example application.
6871
| :--------------------------------------------------------------------------: | :----------------------------------------------------------------------------------: |
6972
| ![plane_indicator](readme/plane_indicator.gif) | ![ice_cream_indicator](readme/ice_cream_indicator.gif) |
7073

71-
| Simple indicator made with `PositionedIndicatorContainer` [[SOURCE CODE](example/lib/indicators/simple_indicator.dart)] | Envelope indicator |
72-
| :---------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------: |
73-
| ![simple_indicator](readme/simple_with_opacity.gif) | ![letter_indicator](readme/letter_indicator.gif) |
74+
| Warp indicator [[SOURCE CODE](example/lib/indicators/warp_indicator.dart)] | Envelope indicator |
75+
| :------------------------------------------------------------------------: | :----------------------------------------------: |
76+
| ![warp_indicator](readme/warp_indicator.gif) | ![letter_indicator](readme/letter_indicator.gif) |
7477

7578
| Indicator with complete state [[SOURCE CODE](example/lib/indicators/check_mark_indicator.dart)] | Your indicator |
7679
| :---------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------: |
7780
| ![indicator_with_complete_state](readme/indicator_with_complete_state.gif) | Have you created a fancy refresh indicator? This place is for you. Open PR. |
7881

79-
80-
81-
8282
# Documentation
8383

8484
## CustomRefreshIndicator widget
@@ -90,7 +90,7 @@ Almost all of these examples are available in the example application.
9090
### Controller state and value changes.
9191

9292
The best way to understand how the "CustomRefreshIndicator" widget changes its controller data is to see the example 😉. An example is available in the example application.
93-
93+
9494
![Controller_Data](readme/controller_data.gif)
9595

9696
| state | value | value description | Description |
@@ -102,34 +102,52 @@ The best way to understand how the "CustomRefreshIndicator" widget changes its c
102102
| **hiding** | `<=1.0` | Value decreses in duration of `draggingToIdleDuration` or `loadingToIdleDuration` arguments to `0.0`. | Indicator is hiding after:<br />- User ended dragging when indicator was in `dragging` state.<br />- Future returned from `onRefresh` function is resolved.<br />- Complete state ended.<br />- User started scrolling through the list. |
103103
| **complete** | `==1.0` | Value equals `1.0` for duration of `completeStateDuration` argument. | **This state is OPTIONAL, provide `completeStateDuration` argument with non null value to enable it.**<br /> Loading is completed. |
104104

105-
___
105+
---
106106

107-
### `didStateChange`
108-
With this method, you can easily check if the indicator's state has changed.
107+
### IndicatorStateHelper
109108

109+
With the IndicatorStateHelper class, you can easily track indicator's state changes. Example usage can be found [HERE](example/lib/indicators/check_mark_indicator.dart).
110+
111+
All you need to do is to update it's value on every controller update.
112+
```dart
113+
CustomRefreshIndicator(
114+
onRefresh: onRefresh,
115+
child: widget.child,
116+
builder: (
117+
BuildContext context,
118+
Widget child,
119+
IndicatorController controller,
120+
) => AnimatedBuilder(
121+
animation: controller,
122+
builder: (BuildContext context, Widget? _) {
123+
/// Now every state change will be tracked by the helper class.
124+
_helper.update(controller.state);
125+
// ...
126+
```
127+
Then you can simply track state changes:
110128
```dart
111129
/// When the state changes to [idle]
112-
if(controller.didStateChange(to: IndicatorState.idle)) {
130+
if(_helper.didStateChange(to: IndicatorState.idle)) {
113131
// Code...
114132
}
115133
116134
/// When the state changes from [idle] to [dragging]
117-
if (controller.didStateChange(
135+
if (_helper.didStateChange(
118136
from: IndicatorState.idle,
119137
to: IndicatorState.dragging,
120138
)) {
121139
// Code...
122140
}
123141
124142
/// When the state changes from [idle] to another.
125-
if (controller.didStateChange(
143+
if (_helper.didStateChange(
126144
from: IndicatorState.idle,
127145
)) {
128146
// Code...
129147
}
130148
131149
/// When the state changes.
132-
if (controller.didStateChange()) {
150+
if (_helper.didStateChange()) {
133151
// Code...
134152
}
135-
```
153+
```

example/lib/indicators/check_mark_indicator.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
22
import 'package:flutter/material.dart';
3+
import 'package:flutter/rendering.dart';
34
import 'package:flutter/widgets.dart';
45

56
class CheckMarkIndicator extends StatefulWidget {
@@ -17,10 +18,14 @@ class CheckMarkIndicator extends StatefulWidget {
1718
class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
1819
with SingleTickerProviderStateMixin {
1920
static const _indicatorSize = 150.0;
21+
final _helper = IndicatorStateHelper();
2022

2123
/// Whether to render check mark instead of spinner
2224
bool _renderCompleteState = false;
2325

26+
27+
ScrollDirection prevScrollDirection = ScrollDirection.idle;
28+
2429
@override
2530
Widget build(BuildContext context) {
2631
return CustomRefreshIndicator(
@@ -38,12 +43,21 @@ class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
3843
AnimatedBuilder(
3944
animation: controller,
4045
builder: (BuildContext context, Widget? _) {
46+
_helper.update(controller.state);
47+
48+
if (controller.scrollingDirection == ScrollDirection.reverse &&
49+
prevScrollDirection == ScrollDirection.forward) {
50+
controller.stopDrag();
51+
}
52+
53+
prevScrollDirection = controller.scrollingDirection;
54+
4155
/// set [_renderCompleteState] to true when controller.state become completed
42-
if (controller.didStateChange(to: IndicatorState.complete)) {
56+
if (_helper.didStateChange(to: IndicatorState.complete)) {
4357
_renderCompleteState = true;
4458

4559
/// set [_renderCompleteState] to false when controller.state become idle
46-
} else if (controller.didStateChange(to: IndicatorState.idle)) {
60+
} else if (_helper.didStateChange(to: IndicatorState.idle)) {
4761
_renderCompleteState = false;
4862
}
4963
final containerHeight = controller.value * _indicatorSize;

0 commit comments

Comments
 (0)