Skip to content

Commit 0899c31

Browse files
authored
Merge pull request #49 from gonuit/release/v3.0.0
v3.0.0
2 parents 465699d + 7611155 commit 0899c31

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1219
-820
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## 3.0.0
2+
- **CustomRefreshIndicator**:
3+
- Deprecated *indicatorFinalizeDuration*, *indicatorSettleDuration*, *indicatorCancelDuration* and *completeStateDuration* parameters in favor of *durations*.
4+
- The indicator widget will now be rebuilt every time *state* changes, even if the *autoRebuilt* parameter is set to false. This will make managing the state of the indicator widget simpler.
5+
- Deprecated *IndicatorDelegate* and *MaterialIndicatorDelegate* in favor of *CustomMaterialIndicator* widget.
6+
- **IndicatorController**:
7+
- The controller now extends *Animation<double>*. This allows it to be used directly with *Transition* widgets to further improve animation performance.
8+
- New *ClampedAnimation* class for constraining the *IndicatorController* animation value within a specific range using the *clamp* method.
9+
- Drag interaction details are now available, enabling pointer-position-based animations.
10+
- **Example app**:
11+
- The checkmark indicator example has been simplified.
12+
- Minor corrections to the envelope indicator.
13+
- Added image precaching.
14+
- Removed unused code.
115
## 2.2.1
216
- Fixed typos in documentation
317
## 2.2.0

README.md

Lines changed: 229 additions & 211 deletions
Large diffs are not rendered by default.

example/lib/indicators/check_mark_indicator.dart

Lines changed: 61 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,120 +2,98 @@ import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter/rendering.dart';
44

5+
class CheckMarkColors {
6+
final Color content;
7+
final Color background;
8+
9+
const CheckMarkColors({
10+
required this.content,
11+
required this.background,
12+
});
13+
}
14+
15+
class CheckMarkStyle {
16+
final CheckMarkColors loading;
17+
final CheckMarkColors completed;
18+
19+
const CheckMarkStyle({
20+
required this.loading,
21+
required this.completed,
22+
});
23+
24+
static const defaultStyle = CheckMarkStyle(
25+
loading: CheckMarkColors(content: Colors.white, background: Colors.black),
26+
completed: CheckMarkColors(content: Colors.white, background: Colors.greenAccent),
27+
);
28+
}
29+
530
class CheckMarkIndicator extends StatefulWidget {
631
final Widget child;
32+
final CheckMarkStyle style;
733

834
const CheckMarkIndicator({
9-
Key? key,
35+
super.key,
1036
required this.child,
11-
}) : super(key: key);
37+
this.style = CheckMarkStyle.defaultStyle,
38+
});
1239

1340
@override
14-
_CheckMarkIndicatorState createState() => _CheckMarkIndicatorState();
41+
State<CheckMarkIndicator> createState() => _CheckMarkIndicatorState();
1542
}
1643

17-
class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
18-
with SingleTickerProviderStateMixin {
19-
static const _indicatorSize = 150.0;
20-
44+
class _CheckMarkIndicatorState extends State<CheckMarkIndicator> with SingleTickerProviderStateMixin {
2145
/// Whether to render check mark instead of spinner
2246
bool _renderCompleteState = false;
2347

2448
ScrollDirection prevScrollDirection = ScrollDirection.idle;
2549

2650
@override
2751
Widget build(BuildContext context) {
28-
return CustomRefreshIndicator(
29-
offsetToArmed: _indicatorSize,
52+
return CustomMaterialIndicator(
53+
withRotation: false,
3054
onRefresh: () => Future.delayed(const Duration(seconds: 2)),
31-
child: widget.child,
32-
completeStateDuration: const Duration(seconds: 2),
55+
durations: const RefreshIndicatorDurations(
56+
completeDuration: Duration(seconds: 2),
57+
),
3358
onStateChanged: (change) {
3459
/// set [_renderCompleteState] to true when controller.state become completed
3560
if (change.didChange(to: IndicatorState.complete)) {
36-
setState(() {
37-
_renderCompleteState = true;
38-
});
61+
_renderCompleteState = true;
3962

4063
/// set [_renderCompleteState] to false when controller.state become idle
4164
} else if (change.didChange(to: IndicatorState.idle)) {
42-
setState(() {
43-
_renderCompleteState = false;
44-
});
65+
_renderCompleteState = false;
4566
}
4667
},
47-
builder: (
68+
indicatorBuilder: (
4869
BuildContext context,
49-
Widget child,
5070
IndicatorController controller,
5171
) {
52-
return Stack(
53-
children: <Widget>[
54-
AnimatedBuilder(
55-
animation: controller,
56-
builder: (BuildContext context, Widget? _) {
57-
if (controller.scrollingDirection == ScrollDirection.reverse &&
58-
prevScrollDirection == ScrollDirection.forward) {
59-
controller.stopDrag();
60-
}
61-
62-
prevScrollDirection = controller.scrollingDirection;
63-
64-
final containerHeight = controller.value * _indicatorSize;
65-
66-
return Container(
67-
alignment: Alignment.center,
68-
height: containerHeight,
69-
child: OverflowBox(
70-
maxHeight: 40,
71-
minHeight: 40,
72-
maxWidth: 40,
73-
minWidth: 40,
74-
alignment: Alignment.center,
75-
child: AnimatedContainer(
76-
duration: const Duration(milliseconds: 150),
77-
alignment: Alignment.center,
78-
child: _renderCompleteState
79-
? const Icon(
80-
Icons.check,
81-
color: Colors.white,
82-
)
83-
: SizedBox(
84-
height: 30,
85-
width: 30,
86-
child: CircularProgressIndicator(
87-
strokeWidth: 2,
88-
valueColor:
89-
const AlwaysStoppedAnimation(Colors.white),
90-
value:
91-
controller.isDragging || controller.isArmed
92-
? controller.value.clamp(0.0, 1.0)
93-
: null,
94-
),
95-
),
96-
decoration: BoxDecoration(
97-
color: _renderCompleteState
98-
? Colors.greenAccent
99-
: Colors.black,
100-
shape: BoxShape.circle,
101-
),
102-
),
72+
final style = _renderCompleteState ? widget.style.completed : widget.style.loading;
73+
return AnimatedContainer(
74+
duration: const Duration(milliseconds: 150),
75+
alignment: Alignment.center,
76+
decoration: BoxDecoration(
77+
color: style.background,
78+
shape: BoxShape.circle,
79+
),
80+
child: _renderCompleteState
81+
? const Icon(
82+
Icons.check,
83+
color: Colors.white,
84+
)
85+
: SizedBox(
86+
height: 24,
87+
width: 24,
88+
child: CircularProgressIndicator(
89+
strokeWidth: 2,
90+
color: style.content,
91+
value: controller.isDragging || controller.isArmed ? controller.value.clamp(0.0, 1.0) : null,
10392
),
104-
);
105-
},
106-
),
107-
AnimatedBuilder(
108-
builder: (context, _) {
109-
return Transform.translate(
110-
offset: Offset(0.0, controller.value * _indicatorSize),
111-
child: child,
112-
);
113-
},
114-
animation: controller,
115-
),
116-
],
93+
),
11794
);
11895
},
96+
child: widget.child,
11997
);
12098
}
12199
}

example/lib/indicators/custom_indicator.dart

Lines changed: 0 additions & 9 deletions
This file was deleted.

example/lib/indicators/envelope_indicator.dart

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,97 +10,93 @@ class EnvelopRefreshIndicator extends StatelessWidget {
1010

1111
static const _circleSize = 70.0;
1212

13-
static const _defaultShadow = [
14-
BoxShadow(blurRadius: 10, color: Colors.black26)
15-
];
13+
static const _blurRadius = 10.0;
14+
static const _defaultShadow = [BoxShadow(blurRadius: _blurRadius, color: Colors.black26)];
1615

1716
const EnvelopRefreshIndicator({
18-
Key? key,
17+
super.key,
1918
required this.child,
2019
required this.onRefresh,
2120
this.leadingScrollIndicatorVisible = false,
2221
this.trailingScrollIndicatorVisible = false,
2322
this.accent,
24-
}) : super(key: key);
23+
});
2524

2625
@override
2726
Widget build(BuildContext context) {
2827
return CustomRefreshIndicator(
2928
leadingScrollIndicatorVisible: leadingScrollIndicatorVisible,
3029
trailingScrollIndicatorVisible: trailingScrollIndicatorVisible,
31-
builder: (context, child, controller) =>
32-
LayoutBuilder(builder: (context, constraints) {
30+
builder: (context, child, controller) => LayoutBuilder(builder: (context, constraints) {
3331
final widgetWidth = constraints.maxWidth;
3432
final widgetHeight = constraints.maxHeight;
3533
final letterTopWidth = (widgetWidth / 2) + 50;
3634

37-
final leftValue =
38-
(widgetWidth - (letterTopWidth * controller.value / 1))
39-
.clamp(letterTopWidth - 100, double.infinity);
35+
final leftValue = (widgetWidth + _blurRadius - ((letterTopWidth + _blurRadius) * controller.value / 1))
36+
.clamp(letterTopWidth - 100, double.infinity);
4037

41-
final rightValue = (widgetWidth - (widgetWidth * controller.value / 1))
42-
.clamp(0.0, double.infinity);
38+
final rightShift = widgetWidth + _blurRadius;
39+
final rightValue = (rightShift - (rightShift * controller.value / 1)).clamp(0.0, double.infinity);
4340

4441
final opacity = (controller.value - 1).clamp(0, 0.5) / 0.5;
42+
43+
final isNotIdle = !controller.isIdle;
4544
return Stack(
4645
children: <Widget>[
4746
Transform.scale(
4847
scale: 1 - 0.1 * controller.value.clamp(0.0, 1.0),
4948
child: child,
5049
),
51-
Positioned(
52-
right: rightValue,
53-
child: Container(
54-
height: widgetHeight,
55-
width: widgetWidth,
56-
decoration: const BoxDecoration(
57-
color: Colors.white,
58-
boxShadow: _defaultShadow,
50+
if (isNotIdle)
51+
Positioned(
52+
right: rightValue,
53+
child: Container(
54+
height: widgetHeight,
55+
width: widgetWidth,
56+
decoration: const BoxDecoration(
57+
color: Colors.white,
58+
boxShadow: _defaultShadow,
59+
),
5960
),
6061
),
61-
),
62-
Positioned(
63-
left: leftValue,
64-
child: CustomPaint(
65-
painter: TrianglePainter(
66-
strokeColor: Colors.white,
67-
paintingStyle: PaintingStyle.fill,
68-
),
69-
child: SizedBox(
70-
height: widgetHeight,
71-
width: letterTopWidth,
62+
if (isNotIdle)
63+
Positioned(
64+
left: leftValue,
65+
child: CustomPaint(
66+
size: Size(
67+
letterTopWidth,
68+
widgetHeight,
69+
),
70+
painter: TrianglePainter(
71+
strokeColor: Colors.white,
72+
paintingStyle: PaintingStyle.fill,
73+
),
7274
),
7375
),
74-
),
7576
if (controller.value >= 1)
7677
Container(
7778
padding: const EdgeInsets.only(right: 100),
7879
child: Transform.scale(
7980
scale: controller.value,
8081
child: Opacity(
81-
opacity: controller.isLoading ? 1 : opacity,
82+
opacity: controller.isLoading || controller.state.isSettling ? 1 : opacity,
8283
child: Align(
8384
alignment: Alignment.center,
8485
child: Container(
8586
width: _circleSize,
8687
height: _circleSize,
8788
decoration: BoxDecoration(
8889
boxShadow: _defaultShadow,
89-
color:
90-
accent ?? Theme.of(context).colorScheme.primary,
90+
color: accent ?? Theme.of(context).colorScheme.primary,
9191
shape: BoxShape.circle,
9292
),
9393
child: Stack(
94+
fit: StackFit.expand,
9495
alignment: Alignment.center,
9596
children: <Widget>[
96-
SizedBox(
97-
height: double.infinity,
98-
width: double.infinity,
99-
child: CircularProgressIndicator(
100-
valueColor:
101-
const AlwaysStoppedAnimation(Colors.black),
102-
value: controller.isLoading ? null : 0,
103-
),
97+
CircularProgressIndicator(
98+
valueColor: const AlwaysStoppedAnimation(Colors.black),
99+
value: controller.isLoading ? null : 0,
104100
),
105101
const Icon(
106102
Icons.mail_outline,
@@ -132,10 +128,7 @@ class TrianglePainter extends CustomPainter {
132128
return radius * 0.57735 + 0.5;
133129
}
134130

135-
TrianglePainter(
136-
{this.strokeColor = Colors.black,
137-
this.strokeWidth = 3,
138-
this.paintingStyle = PaintingStyle.stroke});
131+
TrianglePainter({this.strokeColor = Colors.black, this.strokeWidth = 3, this.paintingStyle = PaintingStyle.stroke});
139132

140133
@override
141134
void paint(Canvas canvas, Size size) {
@@ -146,8 +139,7 @@ class TrianglePainter extends CustomPainter {
146139
final path = getTrianglePath(size.width, size.height);
147140
final shadowPaint = Paint()
148141
..color = Colors.black.withAlpha(50)
149-
..maskFilter =
150-
MaskFilter.blur(BlurStyle.normal, convertRadiusToSigma(10));
142+
..maskFilter = MaskFilter.blur(BlurStyle.normal, convertRadiusToSigma(10));
151143
canvas.drawPath(path, shadowPaint);
152144

153145
canvas.drawPath(path, paint);

0 commit comments

Comments
 (0)