Skip to content

Commit b18d0bb

Browse files
committed
updated page_indicator.dart example for more performance.
1 parent 697798f commit b18d0bb

File tree

3 files changed

+120
-53
lines changed

3 files changed

+120
-53
lines changed

example/lib/demos/page_indicator/dot.dart

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import 'dart:ui';
22

3+
import '../../utils/utils.dart';
34
import 'package:graphx/graphx.dart';
45

56
class PageDot extends GShape {
6-
77
int id;
88

99
double _baseSize;
@@ -18,6 +18,19 @@ class PageDot extends GShape {
1818
_invalidateDraw();
1919
}
2020

21+
Color _targetColor;
22+
23+
Color get targetColor => _targetColor;
24+
25+
GTweenableColor _colorTween;
26+
bool _invalidColor = false;
27+
28+
set targetColor(Color value) {
29+
if (value == _color) return;
30+
_targetColor = value;
31+
_invalidColor = true;
32+
}
33+
2134
double _size;
2235
double targetSize;
2336

@@ -32,11 +45,9 @@ class PageDot extends GShape {
3245
}
3346

3447
PageDot(this.id, double baseSize, Color color) {
35-
// w = h = size;
3648
_color = color;
3749
targetSize = _size = _baseSize = baseSize;
3850
_invalidateDraw();
39-
// _draw();
4051
}
4152

4253
void _draw() {
@@ -62,12 +73,43 @@ class PageDot extends GShape {
6273
@override
6374
void update(double delta) {
6475
super.update(delta);
65-
// _size += (_targetSize-_size)/10;
66-
// _isInvalid=true;
76+
77+
/// We use the internal update() [same as stage.onEnterFrame()] as a
78+
/// validator to call methods in a lazy way.
79+
///
80+
/// This is a lazy invalidation for properties... each time you set a
81+
/// property that changes this flags, it wait til the next TICK cycle to
82+
/// check if it has to run some "heavy" logic.
83+
///
84+
/// For this Dot class, if you set:
85+
/// `for( var i=0;i<10;++i) dot.size = i * 10;`
86+
/// only the internal _size property will change, but the Dot will not
87+
/// be redraw until the next frame, this is a basic save in performance.
88+
///
89+
90+
if (_invalidColor) {
91+
// to run the internal tween
92+
_invalidColor = false;
93+
_applyColorTween();
94+
}
6795
if (_isInvalid) {
6896
_isInvalid = false;
6997
validate();
7098
}
99+
}
100+
101+
void _applyColorTween() {
102+
_invalidColor = false;
71103

104+
/// no need cause the object is recreated, but killing the tween
105+
/// will assure no more tween update cycles will be called for nothing
106+
/// on a dead instance.
107+
if (_colorTween != null) {
108+
GTween.killTweensOf(_colorTween);
109+
}
110+
_colorTween = _color.twn;
111+
_colorTween.tween(_targetColor, duration: .3, onUpdate: () {
112+
color = _colorTween.value;
113+
});
72114
}
73115
}

example/lib/demos/page_indicator/page_indicator.dart

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,39 @@ import 'scene.dart';
88
class PageIndicatorMain extends StatelessWidget {
99
@override
1010
Widget build(BuildContext context) {
11-
return Scaffold(
12-
appBar: AppBar(
13-
centerTitle: false,
14-
title: Text('page indicator'),
15-
elevation: 0,
16-
backgroundColor: Colors.black26,
17-
),
18-
body: Center(
11+
Widget buildPageIndicator() {
12+
return Center(
1913
child: Container(
20-
// width: 300,
14+
width: 100,
15+
height: 20,
2116
child: SceneBuilderWidget(
2217
builder: () => SceneController(
2318
front: PageIndicatorPaged(),
2419
config: SceneConfig.games,
2520
),
2621
),
2722
),
28-
),
29-
);
23+
);
24+
}
25+
26+
/// sample 1, force the amount of Scenes to test
27+
// final body = SingleChildScrollView(
28+
// child: Column(
29+
// children: List.generate(10, (index) => buildPageIndicator()),
30+
// ),
31+
// );
32+
33+
/// sample 2, ListView builder lazily creates as you scroll.
34+
final body =
35+
ListView.builder(itemBuilder: (_, index) => buildPageIndicator());
36+
37+
return Scaffold(
38+
appBar: AppBar(
39+
centerTitle: false,
40+
title: Text('page indicator'),
41+
elevation: 0,
42+
backgroundColor: Colors.black26,
43+
),
44+
body: body);
3045
}
3146
}

example/lib/demos/page_indicator/scene.dart

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ class PageIndicatorPaged extends BaseScene {
1111
PageIndicatorPaged();
1212

1313
List<PageDot> _dots;
14-
static const double dotSize = 27 / 2;
15-
static const double dotPreW = 37 / 2;
16-
static const double dotSelectedW = 69 / 2;
14+
static const double dotSize = 13;
15+
static const double dotPreW = 18;
16+
static const double dotSelectedW = 34;
1717
static const dotUnselectedColor = Color(0xffC4C4C4);
1818
static const dotSelectedColor = Colors.red;
1919
static const dotPreColor = Colors.blue;
@@ -25,14 +25,20 @@ class PageIndicatorPaged extends BaseScene {
2525
final int _visibleItems = 5;
2626
final int _numItems = 10;
2727
int _scroll = 0;
28+
double _allDotsWidth = 0;
29+
2830
double dotSep = 3;
2931

30-
double allDotsWidth = 0;
32+
/// Easing for euler integration.
33+
/// The bigger number, the slower transitions.
34+
double scrollEase = 10;
35+
double dotSizeEase = 10;
36+
double dotPositionEase = 3;
3137

3238
@override
3339
void addedToStage() {
3440
super.addedToStage();
35-
stage.color = Color(0xffD1D1D);
41+
// stage.color = Color(0xffD1D1D);
3642

3743
container = GSprite();
3844
scrollContainer = GSprite();
@@ -47,8 +53,8 @@ class PageIndicatorPaged extends BaseScene {
4753
});
4854

4955
var itemWS = dotSize + dotSep;
50-
allDotsWidth =
51-
itemWS * (_visibleItems - 2) + (dotPreW + dotSep) * 2 + dotSelectedW;
56+
_allDotsWidth =
57+
itemWS * (_visibleItems - 3) + (dotPreW + dotSep) * 2 + dotSelectedW;
5258

5359
/// debug size.
5460
// container.graphics
@@ -58,15 +64,15 @@ class PageIndicatorPaged extends BaseScene {
5864
// .endFill();
5965

6066
/// -- masking.
61-
6267
// var maskOff = 3.0;
6368
// container.maskRect = GRect(
6469
// -maskOff,
6570
// -maskOff,
66-
// allDotsWidth + maskOff * 2,
71+
// _allDotsWidth + maskOff * 2,
6772
// dotSize + maskOff * 2,
6873
// );
6974
// container.maskRect.corners.allTo(dotSize);
75+
7076
/// -- end masking.
7177
7278
/// only for testing.
@@ -80,7 +86,7 @@ class PageIndicatorPaged extends BaseScene {
8086
});
8187

8288
stage.onResized.add(() {
83-
var ratioScale = sw / allDotsWidth;
89+
var ratioScale = sw / _allDotsWidth;
8490
scale = ratioScale;
8591

8692
/// center it (not using alignPivot())
@@ -104,8 +110,7 @@ class PageIndicatorPaged extends BaseScene {
104110
void update(double delta) {
105111
super.update(delta);
106112
_updateScroll();
107-
_resizeItems();
108-
_positionItems();
113+
_layoutDots();
109114
}
110115

111116
set currentIndex(int value) {
@@ -114,8 +119,9 @@ class PageIndicatorPaged extends BaseScene {
114119
_currentIndex = value.clamp(0, _numItems - 1);
115120

116121
/// offset scroll.
117-
if (_currentIndex > _visibleItems - 1) {
118-
var offset = _visibleItems - 1 - _currentIndex;
122+
/// -2 = take off mid size items.
123+
if (_currentIndex > _visibleItems - 2) {
124+
var offset = _visibleItems - 2 - _currentIndex;
119125
_scroll = offset;
120126
if (_currentIndex == _numItems - 1) {
121127
_scroll += 1;
@@ -127,48 +133,52 @@ class PageIndicatorPaged extends BaseScene {
127133
}
128134
var firstIndex = -_scroll;
129135
_dots.forEach((dot) {
130-
double targetAlpha = 1.0;
131-
if (dot.id < firstIndex || dot.id > firstIndex + _visibleItems) {
132-
targetAlpha = 0.3;
136+
var targetAlpha = 1.0;
137+
if (dot.id < firstIndex || dot.id > firstIndex + (_visibleItems - 1)) {
138+
targetAlpha = 0;
133139
}
134140
dot.tween(
135141
duration: .3,
136-
colorize: dotUnselectedColor,
137142
alpha: targetAlpha,
143+
/// for a zoom in effect
144+
// scale: targetAlpha == 1 ? 1 : .25,
145+
// y: targetAlpha == 1 ? 0.0 : dotSize / 2,
138146
);
147+
dot.targetColor = dotUnselectedColor;
139148
dot.targetSize = dotSize;
140149
});
141150

142151
prevDot?.targetSize = dotPreW;
143152
nextDot?.targetSize = dotPreW;
144153

145-
nextDot?.tween(duration: .3, colorize: dotPreColor, overwrite: 0);
146-
prevDot?.tween(duration: .3, colorize: dotPreColor, overwrite: 0);
147-
// nextDot?.color = dotPreColor;
148-
// prevDot?.color = dotPreColor;
149-
154+
/// color is computed internally in the dot to avoid
155+
/// the expensize "colorize".
156+
nextDot?.targetColor = dotPreColor;
157+
prevDot?.targetColor = dotPreColor;
150158
currDot?.targetSize = dotSelectedW;
151-
currDot?.tween(duration: .3, colorize: dotSelectedColor, overwrite: 0);
152-
// _positionItems();
159+
currDot?.targetColor = dotSelectedColor;
153160
}
154161

155-
void _positionItems() {
162+
void _layoutDots() {
156163
var lastX = 0.0;
157164
for (var i = 0; i < _dots.length; ++i) {
158165
var dot = _dots[i];
159-
// dot.x = lastX;
160-
dot.x += (lastX - dot.x) / 4;
166+
var sizeDistance = dot.targetSize - dot.size;
167+
if (sizeDistance.abs() < .1) {
168+
dot.size = dot.targetSize;
169+
} else {
170+
dot.size += sizeDistance / dotSizeEase;
171+
}
172+
var posDistance = lastX - dot.x;
173+
if (posDistance.abs() < .1) {
174+
dot.x = lastX;
175+
} else {
176+
dot.x += posDistance / dotPositionEase;
177+
}
161178
lastX += dot.size + dotSep;
162179
}
163180
}
164181

165-
void _resizeItems() {
166-
for (var i = 0; i < _dots.length; ++i) {
167-
var dot = _dots[i];
168-
dot.size += (dot.targetSize - dot.size) / 10;
169-
}
170-
}
171-
172182
PageDot get currDot {
173183
return _dots[_currentIndex];
174184
}
@@ -185,10 +195,10 @@ class PageIndicatorPaged extends BaseScene {
185195

186196
void _updateScroll() {
187197
var distance = _targetScroll - scrollContainer.x;
188-
if (distance.abs() < .5) {
198+
if (distance.abs() < .1) {
189199
scrollContainer.x = _targetScroll;
190200
return;
191201
}
192-
scrollContainer.x += distance / 12;
202+
scrollContainer.x += distance / scrollEase;
193203
}
194204
}

0 commit comments

Comments
 (0)