blob: a6c63c550c735f8c853b708bb862f1df57266962 [file] [log] [blame]
Hans Muller36eb4a02016-07-21 10:48:41 -07001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:async';
Greg Spencer9749f592019-09-25 14:49:22 -07006import 'dart:io';
Hans Muller36eb4a02016-07-21 10:48:41 -07007
Greg Spencer9749f592019-09-25 14:49:22 -07008import 'package:flutter/foundation.dart';
Hans Muller36eb4a02016-07-21 10:48:41 -07009import 'package:flutter/gestures.dart';
10import 'package:flutter/material.dart';
11
12enum _DragTarget {
13 start,
14 end
15}
16
17// How close a drag's start position must be to the target point. This is
18// a distance squared.
19const double _kTargetSlop = 2500.0;
20
21// Used by the Painter classes.
22const double _kPointRadius = 6.0;
23
24class _DragHandler extends Drag {
25 _DragHandler(this.onUpdate, this.onCancel, this.onEnd);
26
27 final GestureDragUpdateCallback onUpdate;
28 final GestureDragCancelCallback onCancel;
29 final GestureDragEndCallback onEnd;
30
31 @override
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +010032 void update(DragUpdateDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -070033 onUpdate(details);
34 }
35
36 @override
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +010037 void cancel() {
Hans Muller36eb4a02016-07-21 10:48:41 -070038 onCancel();
39 }
40
41 @override
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +010042 void end(DragEndDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -070043 onEnd(details);
44 }
45}
46
47class _IgnoreDrag extends Drag {
48}
49
50class _PointDemoPainter extends CustomPainter {
51 _PointDemoPainter({
52 Animation<double> repaint,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +010053 this.arc,
Hans Muller36eb4a02016-07-21 10:48:41 -070054 }) : _repaint = repaint, super(repaint: repaint);
55
56 final MaterialPointArcTween arc;
Adam Barth7be91152017-04-19 09:30:43 -070057 final Animation<double> _repaint;
Hans Muller36eb4a02016-07-21 10:48:41 -070058
Ian Hicksonbf017b72017-04-12 15:06:12 -070059 void drawPoint(Canvas canvas, Offset point, Color color) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +020060 final Paint paint = Paint()
Hans Muller36eb4a02016-07-21 10:48:41 -070061 ..color = color.withOpacity(0.25)
62 ..style = PaintingStyle.fill;
63 canvas.drawCircle(point, _kPointRadius, paint);
64 paint
65 ..color = color
66 ..style = PaintingStyle.stroke
67 ..strokeWidth = 2.0;
68 canvas.drawCircle(point, _kPointRadius + 1.0, paint);
69 }
70
71 @override
72 void paint(Canvas canvas, Size size) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +020073 final Paint paint = Paint();
Hans Muller36eb4a02016-07-21 10:48:41 -070074
75 if (arc.center != null)
Alexandre Ardhuin578ca0a2017-03-21 23:14:55 +010076 drawPoint(canvas, arc.center, Colors.grey.shade400);
Hans Muller36eb4a02016-07-21 10:48:41 -070077
78 paint
Hans Mullerafc05502016-09-02 16:13:09 -070079 ..isAntiAlias = false // Work-around for github.com/flutter/flutter/issues/5720
Alexandre Ardhuin578ca0a2017-03-21 23:14:55 +010080 ..color = Colors.green.withOpacity(0.25)
Hans Muller36eb4a02016-07-21 10:48:41 -070081 ..strokeWidth = 4.0
82 ..style = PaintingStyle.stroke;
83 if (arc.center != null && arc.radius != null)
84 canvas.drawCircle(arc.center, arc.radius, paint);
85 else
86 canvas.drawLine(arc.begin, arc.end, paint);
87
Alexandre Ardhuin578ca0a2017-03-21 23:14:55 +010088 drawPoint(canvas, arc.begin, Colors.green);
89 drawPoint(canvas, arc.end, Colors.red);
Hans Muller36eb4a02016-07-21 10:48:41 -070090
91 paint
Alexandre Ardhuin578ca0a2017-03-21 23:14:55 +010092 ..color = Colors.green
Hans Muller36eb4a02016-07-21 10:48:41 -070093 ..style = PaintingStyle.fill;
94 canvas.drawCircle(arc.lerp(_repaint.value), _kPointRadius, paint);
95 }
96
97 @override
Ian Hicksonbf017b72017-04-12 15:06:12 -070098 bool hitTest(Offset position) {
Hans Muller36eb4a02016-07-21 10:48:41 -070099 return (arc.begin - position).distanceSquared < _kTargetSlop
100 || (arc.end - position).distanceSquared < _kTargetSlop;
101 }
102
103 @override
104 bool shouldRepaint(_PointDemoPainter oldPainter) => arc != oldPainter.arc;
105}
106
107class _PointDemo extends StatefulWidget {
Alexandre Ardhuin95418482017-04-21 23:09:42 +0200108 const _PointDemo({ Key key, this.controller }) : super(key: key);
Hans Muller36eb4a02016-07-21 10:48:41 -0700109
110 final AnimationController controller;
111
112 @override
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200113 _PointDemoState createState() => _PointDemoState();
Hans Muller36eb4a02016-07-21 10:48:41 -0700114}
115
116class _PointDemoState extends State<_PointDemo> {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200117 final GlobalKey _painterKey = GlobalKey();
Hans Muller36eb4a02016-07-21 10:48:41 -0700118
119 CurvedAnimation _animation;
120 _DragTarget _dragTarget;
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700121 Size _screenSize;
Ian Hicksonbf017b72017-04-12 15:06:12 -0700122 Offset _begin;
123 Offset _end;
Hans Muller36eb4a02016-07-21 10:48:41 -0700124
125 @override
126 void initState() {
127 super.initState();
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200128 _animation = CurvedAnimation(parent: widget.controller, curve: Curves.fastOutSlowIn);
Hans Muller36eb4a02016-07-21 10:48:41 -0700129 }
130
131 @override
132 void dispose() {
xster89a7fdf2017-04-10 18:32:24 -0700133 widget.controller.value = 0.0;
Hans Muller36eb4a02016-07-21 10:48:41 -0700134 super.dispose();
135 }
136
Ian Hicksonbf017b72017-04-12 15:06:12 -0700137 Drag _handleOnStart(Offset position) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700138 // TODO(hansmuller): allow the user to drag both points at the same time.
139 if (_dragTarget != null)
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200140 return _IgnoreDrag();
Hans Muller36eb4a02016-07-21 10:48:41 -0700141
142 final RenderBox box = _painterKey.currentContext.findRenderObject();
143 final double startOffset = (box.localToGlobal(_begin) - position).distanceSquared;
144 final double endOffset = (box.localToGlobal(_end) - position).distanceSquared;
145 setState(() {
146 if (startOffset < endOffset && startOffset < _kTargetSlop)
147 _dragTarget = _DragTarget.start;
148 else if (endOffset < _kTargetSlop)
149 _dragTarget = _DragTarget.end;
150 else
151 _dragTarget = null;
152 });
153
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200154 return _DragHandler(_handleDragUpdate, _handleDragCancel, _handleDragEnd);
Hans Muller36eb4a02016-07-21 10:48:41 -0700155 }
156
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100157 void _handleDragUpdate(DragUpdateDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700158 switch (_dragTarget) {
159 case _DragTarget.start:
160 setState(() {
161 _begin = _begin + details.delta;
162 });
163 break;
164 case _DragTarget.end:
165 setState(() {
166 _end = _end + details.delta;
167 });
168 break;
169 }
170 }
171
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100172 void _handleDragCancel() {
Hans Muller36eb4a02016-07-21 10:48:41 -0700173 _dragTarget = null;
xster89a7fdf2017-04-10 18:32:24 -0700174 widget.controller.value = 0.0;
Hans Muller36eb4a02016-07-21 10:48:41 -0700175 }
176
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100177 void _handleDragEnd(DragEndDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700178 _dragTarget = null;
179 }
180
181 @override
182 Widget build(BuildContext context) {
Hans Mullerd0e72d62016-08-26 15:19:46 -0700183 final Size screenSize = MediaQuery.of(context).size;
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700184 if (_screenSize == null || _screenSize != screenSize) {
185 _screenSize = screenSize;
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200186 _begin = Offset(screenSize.width * 0.5, screenSize.height * 0.2);
187 _end = Offset(screenSize.width * 0.1, screenSize.height * 0.4);
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700188 }
Hans Mullerd0e72d62016-08-26 15:19:46 -0700189
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200190 final MaterialPointArcTween arc = MaterialPointArcTween(begin: _begin, end: _end);
191 return RawGestureDetector(
Hans Muller36eb4a02016-07-21 10:48:41 -0700192 behavior: _dragTarget == null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque,
Adam Barth8a823322016-09-29 08:59:43 -0700193 gestures: <Type, GestureRecognizerFactory>{
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200194 ImmediateMultiDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<ImmediateMultiDragGestureRecognizer>(
195 () => ImmediateMultiDragGestureRecognizer(),
Ian Hickson46b316c2017-06-07 18:04:46 -0700196 (ImmediateMultiDragGestureRecognizer instance) {
197 instance
198 ..onStart = _handleOnStart;
199 },
200 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700201 },
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200202 child: ClipRect(
203 child: CustomPaint(
Hans Muller36eb4a02016-07-21 10:48:41 -0700204 key: _painterKey,
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200205 foregroundPainter: _PointDemoPainter(
Hans Muller36eb4a02016-07-21 10:48:41 -0700206 repaint: _animation,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100207 arc: arc,
Hans Muller36eb4a02016-07-21 10:48:41 -0700208 ),
209 // Watch out: if this IgnorePointer is left out, then gestures that
210 // fail _PointDemoPainter.hitTest() will still be recognized because
211 // they do overlap this child, which is as big as the CustomPaint.
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200212 child: IgnorePointer(
213 child: Padding(
Hans Muller36eb4a02016-07-21 10:48:41 -0700214 padding: const EdgeInsets.all(16.0),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200215 child: Text(
Alexandre Ardhuin1fce14a2017-10-22 18:11:36 +0200216 'Tap the refresh button to run the animation. Drag the green '
Hans Muller36eb4a02016-07-21 10:48:41 -0700217 "and red points to change the animation's path.",
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100218 style: Theme.of(context).textTheme.caption.copyWith(fontSize: 16.0),
219 ),
220 ),
221 ),
222 ),
223 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700224 );
225 }
226}
227
228class _RectangleDemoPainter extends CustomPainter {
229 _RectangleDemoPainter({
230 Animation<double> repaint,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100231 this.arc,
Hans Muller36eb4a02016-07-21 10:48:41 -0700232 }) : _repaint = repaint, super(repaint: repaint);
233
234 final MaterialRectArcTween arc;
Adam Barth7be91152017-04-19 09:30:43 -0700235 final Animation<double> _repaint;
Hans Muller36eb4a02016-07-21 10:48:41 -0700236
Ian Hicksonbf017b72017-04-12 15:06:12 -0700237 void drawPoint(Canvas canvas, Offset p, Color color) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200238 final Paint paint = Paint()
Hans Muller36eb4a02016-07-21 10:48:41 -0700239 ..color = color.withOpacity(0.25)
240 ..style = PaintingStyle.fill;
241 canvas.drawCircle(p, _kPointRadius, paint);
242 paint
243 ..color = color
244 ..style = PaintingStyle.stroke
245 ..strokeWidth = 2.0;
246 canvas.drawCircle(p, _kPointRadius + 1.0, paint);
247 }
248
249 void drawRect(Canvas canvas, Rect rect, Color color) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200250 final Paint paint = Paint()
Hans Muller36eb4a02016-07-21 10:48:41 -0700251 ..color = color.withOpacity(0.25)
252 ..strokeWidth = 4.0
253 ..style = PaintingStyle.stroke;
254 canvas.drawRect(rect, paint);
255 drawPoint(canvas, rect.center, color);
256 }
257
258 @override
259 void paint(Canvas canvas, Size size) {
Alexandre Ardhuin578ca0a2017-03-21 23:14:55 +0100260 drawRect(canvas, arc.begin, Colors.green);
261 drawRect(canvas, arc.end, Colors.red);
262 drawRect(canvas, arc.lerp(_repaint.value), Colors.blue);
Hans Muller36eb4a02016-07-21 10:48:41 -0700263 }
264
265 @override
Ian Hicksonbf017b72017-04-12 15:06:12 -0700266 bool hitTest(Offset position) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700267 return (arc.begin.center - position).distanceSquared < _kTargetSlop
268 || (arc.end.center - position).distanceSquared < _kTargetSlop;
269 }
270
271 @override
272 bool shouldRepaint(_RectangleDemoPainter oldPainter) => arc != oldPainter.arc;
273}
274
275class _RectangleDemo extends StatefulWidget {
Alexandre Ardhuin95418482017-04-21 23:09:42 +0200276 const _RectangleDemo({ Key key, this.controller }) : super(key: key);
Hans Muller36eb4a02016-07-21 10:48:41 -0700277
278 final AnimationController controller;
279
280 @override
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200281 _RectangleDemoState createState() => _RectangleDemoState();
Hans Muller36eb4a02016-07-21 10:48:41 -0700282}
283
284class _RectangleDemoState extends State<_RectangleDemo> {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200285 final GlobalKey _painterKey = GlobalKey();
Hans Muller36eb4a02016-07-21 10:48:41 -0700286
287 CurvedAnimation _animation;
288 _DragTarget _dragTarget;
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700289 Size _screenSize;
Matt Perry82b55c52016-08-08 11:52:35 -0400290 Rect _begin;
291 Rect _end;
Hans Muller36eb4a02016-07-21 10:48:41 -0700292
293 @override
294 void initState() {
295 super.initState();
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200296 _animation = CurvedAnimation(parent: widget.controller, curve: Curves.fastOutSlowIn);
Hans Muller36eb4a02016-07-21 10:48:41 -0700297 }
298
299 @override
300 void dispose() {
xster89a7fdf2017-04-10 18:32:24 -0700301 widget.controller.value = 0.0;
Hans Muller36eb4a02016-07-21 10:48:41 -0700302 super.dispose();
303 }
304
Ian Hicksonbf017b72017-04-12 15:06:12 -0700305 Drag _handleOnStart(Offset position) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700306 // TODO(hansmuller): allow the user to drag both points at the same time.
307 if (_dragTarget != null)
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200308 return _IgnoreDrag();
Hans Muller36eb4a02016-07-21 10:48:41 -0700309
310 final RenderBox box = _painterKey.currentContext.findRenderObject();
311 final double startOffset = (box.localToGlobal(_begin.center) - position).distanceSquared;
312 final double endOffset = (box.localToGlobal(_end.center) - position).distanceSquared;
313 setState(() {
314 if (startOffset < endOffset && startOffset < _kTargetSlop)
315 _dragTarget = _DragTarget.start;
316 else if (endOffset < _kTargetSlop)
317 _dragTarget = _DragTarget.end;
318 else
319 _dragTarget = null;
320 });
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200321 return _DragHandler(_handleDragUpdate, _handleDragCancel, _handleDragEnd);
Hans Muller36eb4a02016-07-21 10:48:41 -0700322 }
323
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100324 void _handleDragUpdate(DragUpdateDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700325 switch (_dragTarget) {
326 case _DragTarget.start:
327 setState(() {
328 _begin = _begin.shift(details.delta);
329 });
330 break;
331 case _DragTarget.end:
332 setState(() {
333 _end = _end.shift(details.delta);
334 });
335 break;
336 }
337 }
338
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100339 void _handleDragCancel() {
Hans Muller36eb4a02016-07-21 10:48:41 -0700340 _dragTarget = null;
xster89a7fdf2017-04-10 18:32:24 -0700341 widget.controller.value = 0.0;
Hans Muller36eb4a02016-07-21 10:48:41 -0700342 }
343
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100344 void _handleDragEnd(DragEndDetails details) {
Hans Muller36eb4a02016-07-21 10:48:41 -0700345 _dragTarget = null;
346 }
347
348 @override
349 Widget build(BuildContext context) {
Hans Mullerd0e72d62016-08-26 15:19:46 -0700350 final Size screenSize = MediaQuery.of(context).size;
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700351 if (_screenSize == null || _screenSize != screenSize) {
352 _screenSize = screenSize;
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200353 _begin = Rect.fromLTWH(
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700354 screenSize.width * 0.5, screenSize.height * 0.2,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100355 screenSize.width * 0.4, screenSize.height * 0.2,
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700356 );
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200357 _end = Rect.fromLTWH(
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700358 screenSize.width * 0.1, screenSize.height * 0.4,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100359 screenSize.width * 0.3, screenSize.height * 0.3,
Hans Mullerf27fa0e2016-09-01 14:07:22 -0700360 );
361 }
Hans Mullerd0e72d62016-08-26 15:19:46 -0700362
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200363 final MaterialRectArcTween arc = MaterialRectArcTween(begin: _begin, end: _end);
364 return RawGestureDetector(
Hans Muller36eb4a02016-07-21 10:48:41 -0700365 behavior: _dragTarget == null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque,
366 gestures: <Type, GestureRecognizerFactory>{
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200367 ImmediateMultiDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<ImmediateMultiDragGestureRecognizer>(
368 () => ImmediateMultiDragGestureRecognizer(),
Ian Hickson46b316c2017-06-07 18:04:46 -0700369 (ImmediateMultiDragGestureRecognizer instance) {
370 instance
371 ..onStart = _handleOnStart;
372 },
373 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700374 },
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200375 child: ClipRect(
376 child: CustomPaint(
Hans Muller36eb4a02016-07-21 10:48:41 -0700377 key: _painterKey,
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200378 foregroundPainter: _RectangleDemoPainter(
Hans Muller36eb4a02016-07-21 10:48:41 -0700379 repaint: _animation,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100380 arc: arc,
Hans Muller36eb4a02016-07-21 10:48:41 -0700381 ),
382 // Watch out: if this IgnorePointer is left out, then gestures that
383 // fail _RectDemoPainter.hitTest() will still be recognized because
384 // they do overlap this child, which is as big as the CustomPaint.
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200385 child: IgnorePointer(
386 child: Padding(
Hans Muller36eb4a02016-07-21 10:48:41 -0700387 padding: const EdgeInsets.all(16.0),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200388 child: Text(
Alexandre Ardhuin1fce14a2017-10-22 18:11:36 +0200389 'Tap the refresh button to run the animation. Drag the rectangles '
Hans Muller36eb4a02016-07-21 10:48:41 -0700390 "to change the animation's path.",
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100391 style: Theme.of(context).textTheme.caption.copyWith(fontSize: 16.0),
392 ),
393 ),
394 ),
395 ),
396 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700397 );
398 }
399}
400
Alexandre Ardhuina07d3712018-09-14 21:06:19 +0200401typedef _DemoBuilder = Widget Function(_ArcDemo demo);
Hans Muller36eb4a02016-07-21 10:48:41 -0700402
403class _ArcDemo {
Alexandre Ardhuina9ba0e22017-03-15 18:30:55 +0100404 _ArcDemo(this.title, this.builder, TickerProvider vsync)
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200405 : controller = AnimationController(duration: const Duration(milliseconds: 500), vsync: vsync),
406 key = GlobalKey(debugLabel: title);
Hans Muller36eb4a02016-07-21 10:48:41 -0700407
Hans Muller36eb4a02016-07-21 10:48:41 -0700408 final String title;
409 final _DemoBuilder builder;
Ian Hickson9e673852016-09-26 10:57:10 -0700410 final AnimationController controller;
Hans Muller36eb4a02016-07-21 10:48:41 -0700411 final GlobalKey key;
412}
413
414class AnimationDemo extends StatefulWidget {
Alexandre Ardhuin95418482017-04-21 23:09:42 +0200415 const AnimationDemo({ Key key }) : super(key: key);
Hans Muller36eb4a02016-07-21 10:48:41 -0700416
Hans Muller36eb4a02016-07-21 10:48:41 -0700417 @override
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200418 _AnimationDemoState createState() => _AnimationDemoState();
Hans Muller36eb4a02016-07-21 10:48:41 -0700419}
420
Ian Hickson9e673852016-09-26 10:57:10 -0700421class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateMixin {
Ian Hickson9e673852016-09-26 10:57:10 -0700422 List<_ArcDemo> _allDemos;
423
424 @override
425 void initState() {
426 super.initState();
427 _allDemos = <_ArcDemo>[
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200428 _ArcDemo('POINT', (_ArcDemo demo) {
429 return _PointDemo(
Ian Hickson9e673852016-09-26 10:57:10 -0700430 key: demo.key,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100431 controller: demo.controller,
Ian Hickson9e673852016-09-26 10:57:10 -0700432 );
433 }, this),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200434 _ArcDemo('RECTANGLE', (_ArcDemo demo) {
435 return _RectangleDemo(
Ian Hickson9e673852016-09-26 10:57:10 -0700436 key: demo.key,
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100437 controller: demo.controller,
Ian Hickson9e673852016-09-26 10:57:10 -0700438 );
439 }, this),
440 ];
441 }
Hans Muller36eb4a02016-07-21 10:48:41 -0700442
Alexandre Ardhuind340e2f2018-10-04 18:44:23 +0200443 Future<void> _play(_ArcDemo demo) async {
Hans Muller36eb4a02016-07-21 10:48:41 -0700444 await demo.controller.forward();
445 if (demo.key.currentState != null && demo.key.currentState.mounted)
446 demo.controller.reverse();
447 }
448
449 @override
450 Widget build(BuildContext context) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200451 return DefaultTabController(
Hans Mullerb23aed72017-01-09 14:55:36 -0800452 length: _allDemos.length,
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200453 child: Scaffold(
454 appBar: AppBar(
Ian Hickson3eb87832017-04-07 12:24:32 -0700455 title: const Text('Animation'),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200456 bottom: TabBar(
Alexandre Ardhuinf62afdc2018-10-01 21:29:08 +0200457 tabs: _allDemos.map<Tab>((_ArcDemo demo) => Tab(text: demo.title)).toList(),
Hans Mullerb23aed72017-01-09 14:55:36 -0800458 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700459 ),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200460 floatingActionButton: Builder(
Hans Mullerb23aed72017-01-09 14:55:36 -0800461 builder: (BuildContext context) {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200462 return FloatingActionButton(
Alexandre Ardhuin610955f2017-04-08 08:43:19 +0200463 child: const Icon(Icons.refresh),
Hans Mullerb23aed72017-01-09 14:55:36 -0800464 onPressed: () {
465 _play(_allDemos[DefaultTabController.of(context).index]);
466 },
467 );
468 },
Hans Muller36eb4a02016-07-21 10:48:41 -0700469 ),
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200470 body: TabBarView(
Alexandre Ardhuin387f8852019-03-01 08:17:55 +0100471 children: _allDemos.map<Widget>((_ArcDemo demo) => demo.builder(demo)).toList(),
472 ),
473 ),
Hans Muller36eb4a02016-07-21 10:48:41 -0700474 );
475 }
476}
Adam Barth8a823322016-09-29 08:59:43 -0700477
478void main() {
Greg Spencer9749f592019-09-25 14:49:22 -0700479 if (Platform.isMacOS) {
480 // TODO(gspencergoog): Update this when TargetPlatform includes macOS. https://github.com/flutter/flutter/issues/31366
481 // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
482 debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
483 }
484
Dan Fieldea5435c2018-09-25 13:57:12 -0400485 runApp(const MaterialApp(
486 home: AnimationDemo(),
Adam Barth8a823322016-09-29 08:59:43 -0700487 ));
488}