Skip to content

Commit 20a2d95

Browse files
gonuitKamil Klyta
andauthored
0.9.0 (#7)
* Add optional complete state * Add previousState controller property and `was...` getterss * Add didStateChange controller helper method * Update pubspec.lock files * Init check mark indicator example * Add notificationPredicate property * Remove unnecessary controller from check_mark_indicator * Update package version and changelog * Add assert whether both extentPercentageToArmed and offsetToArmed arguments are provided. * add isComplete and wasComplete properties * update changelog * remove axis property as it can be handled by notificationPredicate * update changelog * dev.2 * Improve IndicatorController state documentation * prepare new package version * remove material package import * Add didStateChange controller method documentation Co-authored-by: Kamil Klyta <kamil.klyta@htdevelopers.com>
1 parent 20d9e1e commit 20a2d95

13 files changed

+387
-250
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
## [0.9.0] - October 02, 2020
2+
- Improved readme documentation.
3+
- Removed material package import.
4+
## [0.9.0-dev.2] - August 21, 2020
5+
- Added `isComplete` and `wasComplete` controller getters.
6+
- Removed `axis` property as it can be handled by `notificationPredicate`.
7+
## [0.9.0-dev.1] - August 12, 2020
8+
- Added optional `complete` indicator state together with `completeStateDuration` parameter.
9+
- `IndicatorControler` changes:
10+
- Added `prevoiusState` property.
11+
- Added `didStateChange` helper method.
12+
- Added `wasArmed`, `wasDragging`, `wasLoading`, `wasHiding` and `wasIdle` properties.
13+
- Added `notificationPredicate` property to the `CustomRefreshIndicator` widget.
14+
- Example app:
15+
- Added initial version of `check_mark_indicator`. Example that shows how to make use of `complete` state.
16+
117
## [0.8.0+1] - April 12, 2020
218

319
## BREAKING API CHANGES

README.md

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@ If there is something that can be improved, fixed or you just have some great id
66

77
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).
88

9-
## QUICK START
10-
11-
### Code
9+
### Table of Contents
10+
- [Flutter Custom Refresh Indicator](#flutter-custom-refresh-indicator)
11+
- [Table of Contents](#table-of-contents)
12+
- [QUICK START](#quick-start)
13+
- [Examples](#examples)
14+
- [Plane indicator [SOURCE CODE]](#plane-indicator-source-code)
15+
- [Ice cream indicator [SOURCE CODE]](#ice-cream-indicator-source-code)
16+
- [Simple indicator made with `PositionedIndicatorContainer` [SOURCE CODE]](#simple-indicator-made-with-positionedindicatorcontainer-source-code)
17+
- [Envelope indicator](#envelope-indicator)
18+
- [Emoji indicator [SOURCE CODE]](#emoji-indicator-source-code)
19+
- [Indicator with complete state [SOURCE CODE]](#indicator-with-complete-state-source-code)
20+
- [Documentation](#documentation)
21+
- [CustomRefreshIndicator widget](#customrefreshindicator-widget)
22+
- [IndicatorController](#indicatorcontroller)
23+
- [Controller state and value changes.](#controller-state-and-value-changes)
24+
- [`didStateChange`](#didstatechange)
25+
26+
# QUICK START
1227

1328
```dart
1429
CustomRefreshIndicator(
@@ -51,88 +66,87 @@ CustomRefreshIndicator(
5166
)
5267
```
5368

54-
### How the controller data change
55-
56-
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.
57-
58-
![Controller_Data](readme/controller_data.gif)
59-
60-
## Examples
69+
# Examples
6170

6271
Almost all of these examples are available in the example application.
6372

6473
### Plane indicator [[SOURCE CODE](example/lib/indicators/plane_indicator.dart)]
65-
6674
![plane_indicator](readme/plane_indicator.gif)
75+
___
6776

6877
### Ice cream indicator [[SOURCE CODE](example/lib/indicators/ice_cream_indicator.dart)]
69-
7078
![ice_cream_indicator](readme/ice_cream_indicator.gif)
79+
___
7180

7281
### Simple indicator made with `PositionedIndicatorContainer` [[SOURCE CODE](example/lib/indicators/simple_indicator.dart)]
73-
7482
![simple_indicator](readme/simple_with_opacity.gif)
83+
___
7584

7685
### Envelope indicator
77-
7886
![letter_indicator](readme/letter_indicator.gif)
87+
___
7988

8089
### Emoji indicator [[SOURCE CODE](example/lib/indicators/emoji_indicator.dart)]
81-
8290
You can create any indicator you want!
83-
91+
8492
![letter_indicator](readme/emoji_indicator.gif)
93+
___
8594

86-
## CustomRefreshIndicator widget
87-
88-
`CustomRefreshIndicator` widget provides an absolute minimum functionality that allows you to create and set your own custom indicators.
89-
90-
## IndicatorState
91-
92-
Enum which describes state of CustomRefreshIndicator. It is provided by IndicatorController.
93-
94-
#### `idle`
95+
### Indicator with complete state [[SOURCE CODE](example/lib/indicators/check_mark_indicator.dart)]
96+
![indicator_with_complete_state](readme/indicator_with_complete_state.gif)
97+
___
9598

96-
CustomRefreshIndicator is idle (There is no action)
99+
# Documentation
97100

98-
```dart
99-
controller.value == 0.0
100-
```
101-
102-
#### `dragging`
103-
104-
Whether the user is dragging a scrollable widget.
105-
Ending the scroll **WILL NOT** result in `onRefresh` function call
106-
107-
```dart
108-
controller.value < 1.0
109-
```
110-
111-
#### `armed`
112-
113-
CustomRefreshIndicator is armed ending the scroll **WILL** result in:
101+
## CustomRefreshIndicator widget
114102

115-
- `onRefresh` function call
116-
- change of indicator status to `loading`
117-
- decreasing controller.value to `1.0` in duration specified by `armedToLoadingDuration` CustomRefreshIndicator widget argument
103+
`CustomRefreshIndicator` widget provides an absolute minimum functionality that allows you to create and set your own custom indicators.
118104

119-
```dart
120-
controller.value >= 1.0
121-
```
105+
## IndicatorController
122106

123-
#### `hiding`
107+
### Controller state and value changes.
124108

125-
CustomRefreshIndicator is hiding its indicator. After the future returned from `onRefresh` function is completed or scroll ended when the state was equal to `dragging` or the user started scrolling through the list.
126-
controller value decreases to `0.0` in duration specified by `draggingToIdleDuration` CustomRefreshIndicator widget argument.
109+
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.
110+
111+
![Controller_Data](readme/controller_data.gif)
127112

128-
```dart
129-
controller.value <= 1.0
130-
```
113+
| state | value | value description | Description |
114+
| ------------ | :------ | :------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115+
| **idle** | `==0.0` | Value eqals `0.0`. | No user action. |
116+
| **dragging** | `=<0.0` | Value is eqal `0.0` or larger but lower than `1.0`. | User is dragging the indicator. |
117+
| **armed** | `>=1.0` | Value is larger than `1.0`. | User dragged the indicator further than the distance declared by `extentPercentageToArmed` or `offsetToArmed`. User still keeps the finger on the screen. |
118+
| **loading** | `>=1.0` | Value decreses from last `armed` state value in duration of `armedToLoadingDuration` argument to `1.0`. | User finished dragging (took his finger off the screen), when state was equal to `armed`. `onRefresh` function is called. |
119+
| **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. |
120+
| **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. |
131121

132-
#### `loading`
122+
___
133123

134-
CustomRefreshIndicator widget is awaiting on future returned from `onRefresh` function. After future completed state will be change into `hiding` and controller value will decrease from `1.0` to `0.0` in duration specified by `loadingToIdleDuration` CustomRefreshIndicator widget argument.
124+
### `didStateChange`
125+
With this method, you can easily check if the indicator's state has changed.
135126

136127
```dart
137-
controller.value == 1.0
138-
```
128+
/// When the state changes to [idle]
129+
if(controller.didStateChange(to: IndicatorState.idle)) {
130+
// Code...
131+
}
132+
133+
/// When the state changes from [idle] to [dragging]
134+
if (controller.didStateChange(
135+
from: IndicatorState.idle,
136+
to: IndicatorState.dragging,
137+
)) {
138+
// Code...
139+
}
140+
141+
/// When the state changes from [idle] to another.
142+
if (controller.didStateChange(
143+
from: IndicatorState.idle,
144+
)) {
145+
// Code...
146+
}
147+
148+
/// When the state changes.
149+
if (controller.didStateChange()) {
150+
// Code...
151+
}
152+
```
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter/widgets.dart';
4+
5+
class CheckMarkIndicator extends StatefulWidget {
6+
final Widget child;
7+
8+
const CheckMarkIndicator({
9+
Key key,
10+
@required this.child,
11+
}) : super(key: key);
12+
13+
@override
14+
_CheckMarkIndicatorState createState() => _CheckMarkIndicatorState();
15+
}
16+
17+
class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
18+
with SingleTickerProviderStateMixin {
19+
static const _indicatorSize = 150.0;
20+
21+
/// Whether to render check mark instead of spinner
22+
bool _renderCompleteState = false;
23+
24+
@override
25+
Widget build(BuildContext context) {
26+
return CustomRefreshIndicator(
27+
offsetToArmed: _indicatorSize,
28+
onRefresh: () => Future.delayed(const Duration(seconds: 2)),
29+
child: widget.child,
30+
completeStateDuration: const Duration(seconds: 2),
31+
builder: (
32+
BuildContext context,
33+
Widget child,
34+
IndicatorController controller,
35+
) {
36+
return Stack(
37+
children: <Widget>[
38+
AnimatedBuilder(
39+
animation: controller,
40+
builder: (BuildContext context, Widget _) {
41+
/// set [_renderCompleteState] to true when controller.state become completed
42+
if (controller.didStateChange(to: IndicatorState.complete)) {
43+
_renderCompleteState = true;
44+
45+
/// set [_renderCompleteState] to false when controller.state become idle
46+
} else if (controller.didStateChange(to: IndicatorState.idle)) {
47+
_renderCompleteState = false;
48+
}
49+
final containerHeight = controller.value * _indicatorSize;
50+
51+
return Container(
52+
alignment: Alignment.center,
53+
height: containerHeight,
54+
child: OverflowBox(
55+
maxHeight: 40,
56+
minHeight: 40,
57+
maxWidth: 40,
58+
minWidth: 40,
59+
alignment: Alignment.center,
60+
child: AnimatedContainer(
61+
duration: const Duration(milliseconds: 150),
62+
alignment: Alignment.center,
63+
child: _renderCompleteState
64+
? const Icon(
65+
Icons.check,
66+
color: Colors.white,
67+
)
68+
: SizedBox(
69+
height: 30,
70+
width: 30,
71+
child: CircularProgressIndicator(
72+
strokeWidth: 2,
73+
valueColor:
74+
AlwaysStoppedAnimation(Colors.white),
75+
value:
76+
controller.isDragging || controller.isArmed
77+
? controller.value.clamp(0.0, 1.0)
78+
: null,
79+
),
80+
),
81+
decoration: BoxDecoration(
82+
color: _renderCompleteState
83+
? Colors.greenAccent
84+
: Colors.black,
85+
shape: BoxShape.circle,
86+
),
87+
),
88+
),
89+
);
90+
},
91+
),
92+
AnimatedBuilder(
93+
builder: (context, _) {
94+
return Transform.translate(
95+
offset: Offset(0.0, controller.value * _indicatorSize),
96+
child: child,
97+
);
98+
},
99+
animation: controller,
100+
),
101+
],
102+
);
103+
},
104+
);
105+
}
106+
}

example/lib/main.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'indicators/simple_indicator.dart';
66
import 'screens/example_indicator_screen.dart';
77
import 'screens/ice_cream_indicator_screen.dart';
88
import 'screens/plane_indicator_screen.dart';
9+
import 'screens/check_mark_indicator_screen.dart';
910

1011
void main() => runApp(MyApp());
1112

@@ -23,6 +24,7 @@ class MyApp extends StatelessWidget {
2324
'/plane': (context) => PlaneIndicatorScreen(),
2425
'/ice_cream': (context) => IceCreamIndicatorScreen(),
2526
'/presentation': (context) => PresentationScreen(),
27+
'/check-mark': (context) => CheckMarkIndicatorScreen(),
2628
},
2729
);
2830
}
@@ -101,6 +103,18 @@ class MainScreen extends StatelessWidget {
101103
),
102104
),
103105
const SizedBox(height: 15),
106+
RaisedButton(
107+
child: Container(
108+
height: 50,
109+
alignment: Alignment.center,
110+
child: Text("Check mark"),
111+
),
112+
onPressed: () => Navigator.pushNamed(
113+
context,
114+
'/check-mark',
115+
),
116+
),
117+
const SizedBox(height: 15),
104118
RaisedButton(
105119
child: Container(
106120
height: 50,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:example/indicators/check_mark_indicator.dart';
2+
import 'package:example/widgets/example_app_bar.dart';
3+
import 'package:example/widgets/example_list.dart';
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter/widgets.dart';
6+
7+
class CheckMarkIndicatorScreen extends StatefulWidget {
8+
@override
9+
_CheckMarkIndicatorScreenState createState() =>
10+
_CheckMarkIndicatorScreenState();
11+
}
12+
13+
class _CheckMarkIndicatorScreenState extends State<CheckMarkIndicatorScreen> {
14+
@override
15+
Widget build(BuildContext context) {
16+
return Scaffold(
17+
backgroundColor: appBackgroundColor,
18+
appBar: const ExampleAppBar(),
19+
body: SafeArea(
20+
child: CheckMarkIndicator(
21+
child: const ExampleList(),
22+
),
23+
),
24+
);
25+
}
26+
}

0 commit comments

Comments
 (0)