1// Copyright 2015 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 'package:flutter/material.dart'; 6 7import '../../gallery/demo.dart'; 8 9class ProgressIndicatorDemo extends StatefulWidget { 10 static const String routeName = '/material/progress-indicator'; 11 12 @override 13 _ProgressIndicatorDemoState createState() => _ProgressIndicatorDemoState(); 14} 15 16class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> with SingleTickerProviderStateMixin { 17 AnimationController _controller; 18 Animation<double> _animation; 19 20 @override 21 void initState() { 22 super.initState(); 23 _controller = AnimationController( 24 duration: const Duration(milliseconds: 1500), 25 vsync: this, 26 animationBehavior: AnimationBehavior.preserve, 27 )..forward(); 28 29 _animation = CurvedAnimation( 30 parent: _controller, 31 curve: const Interval(0.0, 0.9, curve: Curves.fastOutSlowIn), 32 reverseCurve: Curves.fastOutSlowIn, 33 )..addStatusListener((AnimationStatus status) { 34 if (status == AnimationStatus.dismissed) 35 _controller.forward(); 36 else if (status == AnimationStatus.completed) 37 _controller.reverse(); 38 }); 39 } 40 41 @override 42 void dispose() { 43 _controller.stop(); 44 super.dispose(); 45 } 46 47 void _handleTap() { 48 setState(() { 49 // valueAnimation.isAnimating is part of our build state 50 if (_controller.isAnimating) { 51 _controller.stop(); 52 } else { 53 switch (_controller.status) { 54 case AnimationStatus.dismissed: 55 case AnimationStatus.forward: 56 _controller.forward(); 57 break; 58 case AnimationStatus.reverse: 59 case AnimationStatus.completed: 60 _controller.reverse(); 61 break; 62 } 63 } 64 }); 65 } 66 67 Widget _buildIndicators(BuildContext context, Widget child) { 68 final List<Widget> indicators = <Widget>[ 69 const SizedBox( 70 width: 200.0, 71 child: LinearProgressIndicator(), 72 ), 73 const LinearProgressIndicator(), 74 const LinearProgressIndicator(), 75 LinearProgressIndicator(value: _animation.value), 76 Row( 77 mainAxisAlignment: MainAxisAlignment.spaceEvenly, 78 children: <Widget>[ 79 const CircularProgressIndicator(), 80 SizedBox( 81 width: 20.0, 82 height: 20.0, 83 child: CircularProgressIndicator(value: _animation.value), 84 ), 85 SizedBox( 86 width: 100.0, 87 height: 20.0, 88 child: Text('${(_animation.value * 100.0).toStringAsFixed(1)}%', 89 textAlign: TextAlign.right, 90 ), 91 ), 92 ], 93 ), 94 ]; 95 return Column( 96 children: indicators 97 .map<Widget>((Widget c) => Container(child: c, margin: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 20.0))) 98 .toList(), 99 ); 100 } 101 102 @override 103 Widget build(BuildContext context) { 104 return Scaffold( 105 appBar: AppBar( 106 title: const Text('Progress indicators'), 107 actions: <Widget>[MaterialDemoDocumentationButton(ProgressIndicatorDemo.routeName)], 108 ), 109 body: Center( 110 child: SingleChildScrollView( 111 child: DefaultTextStyle( 112 style: Theme.of(context).textTheme.title, 113 child: GestureDetector( 114 onTap: _handleTap, 115 behavior: HitTestBehavior.opaque, 116 child: SafeArea( 117 top: false, 118 bottom: false, 119 child: Container( 120 padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0), 121 child: AnimatedBuilder( 122 animation: _animation, 123 builder: _buildIndicators, 124 ), 125 ), 126 ), 127 ), 128 ), 129 ), 130 ), 131 ); 132 } 133} 134