• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7class _GesturePainter extends CustomPainter {
8  const _GesturePainter({
9    this.zoom,
10    this.offset,
11    this.swatch,
12    this.forward,
13    this.scaleEnabled,
14    this.tapEnabled,
15    this.doubleTapEnabled,
16    this.longPressEnabled,
17  });
18
19  final double zoom;
20  final Offset offset;
21  final MaterialColor swatch;
22  final bool forward;
23  final bool scaleEnabled;
24  final bool tapEnabled;
25  final bool doubleTapEnabled;
26  final bool longPressEnabled;
27
28  @override
29  void paint(Canvas canvas, Size size) {
30    final Offset center = size.center(Offset.zero) * zoom + offset;
31    final double radius = size.width / 2.0 * zoom;
32    final Gradient gradient = RadialGradient(
33      colors: forward ? <Color>[swatch.shade50, swatch.shade900]
34                      : <Color>[swatch.shade900, swatch.shade50]
35    );
36    final Paint paint = Paint()
37      ..shader = gradient.createShader(Rect.fromCircle(
38        center: center,
39        radius: radius,
40      ));
41    canvas.drawCircle(center, radius, paint);
42  }
43
44  @override
45  bool shouldRepaint(_GesturePainter oldPainter) {
46    return oldPainter.zoom != zoom
47        || oldPainter.offset != offset
48        || oldPainter.swatch != swatch
49        || oldPainter.forward != forward
50        || oldPainter.scaleEnabled != scaleEnabled
51        || oldPainter.tapEnabled != tapEnabled
52        || oldPainter.doubleTapEnabled != doubleTapEnabled
53        || oldPainter.longPressEnabled != longPressEnabled;
54  }
55}
56
57class GestureDemo extends StatefulWidget {
58  @override
59  GestureDemoState createState() => GestureDemoState();
60}
61
62class GestureDemoState extends State<GestureDemo> {
63
64  Offset _startingFocalPoint;
65
66  Offset _previousOffset;
67  Offset _offset = Offset.zero;
68
69  double _previousZoom;
70  double _zoom = 1.0;
71
72  static const List<MaterialColor> kSwatches = <MaterialColor>[
73    Colors.red,
74    Colors.pink,
75    Colors.purple,
76    Colors.deepPurple,
77    Colors.indigo,
78    Colors.blue,
79    Colors.lightBlue,
80    Colors.cyan,
81    Colors.green,
82    Colors.lightGreen,
83    Colors.lime,
84    Colors.yellow,
85    Colors.amber,
86    Colors.orange,
87    Colors.deepOrange,
88    Colors.brown,
89    Colors.grey,
90    Colors.blueGrey,
91  ];
92  int _swatchIndex = 0;
93  MaterialColor _swatch = kSwatches.first;
94  MaterialColor get swatch => _swatch;
95
96  bool _forward = true;
97  bool _scaleEnabled = true;
98  bool _tapEnabled = true;
99  bool _doubleTapEnabled = true;
100  bool _longPressEnabled = true;
101
102  void _handleScaleStart(ScaleStartDetails details) {
103    setState(() {
104      _startingFocalPoint = details.focalPoint;
105      _previousOffset = _offset;
106      _previousZoom = _zoom;
107    });
108  }
109
110  void _handleScaleUpdate(ScaleUpdateDetails details) {
111    setState(() {
112      _zoom = _previousZoom * details.scale;
113
114      // Ensure that item under the focal point stays in the same place despite zooming
115      final Offset normalizedOffset = (_startingFocalPoint - _previousOffset) / _previousZoom;
116      _offset = details.focalPoint - normalizedOffset * _zoom;
117    });
118  }
119
120  void _handleScaleReset() {
121    setState(() {
122      _zoom = 1.0;
123      _offset = Offset.zero;
124    });
125  }
126
127  void _handleColorChange() {
128    setState(() {
129      _swatchIndex += 1;
130      if (_swatchIndex == kSwatches.length)
131        _swatchIndex = 0;
132      _swatch = kSwatches[_swatchIndex];
133    });
134  }
135
136  void _handleDirectionChange() {
137    setState(() {
138      _forward = !_forward;
139    });
140  }
141
142  @override
143  Widget build(BuildContext context) {
144    return Stack(
145      fit: StackFit.expand,
146      children: <Widget>[
147        GestureDetector(
148          onScaleStart: _scaleEnabled ? _handleScaleStart : null,
149          onScaleUpdate: _scaleEnabled ? _handleScaleUpdate : null,
150          onTap: _tapEnabled ? _handleColorChange : null,
151          onDoubleTap: _doubleTapEnabled ? _handleScaleReset : null,
152          onLongPress: _longPressEnabled ? _handleDirectionChange : null,
153          child: CustomPaint(
154            painter: _GesturePainter(
155              zoom: _zoom,
156              offset: _offset,
157              swatch: swatch,
158              forward: _forward,
159              scaleEnabled: _scaleEnabled,
160              tapEnabled: _tapEnabled,
161              doubleTapEnabled: _doubleTapEnabled,
162              longPressEnabled: _longPressEnabled,
163            ),
164          ),
165        ),
166        Positioned(
167          bottom: 0.0,
168          left: 0.0,
169          child: Card(
170            child: Container(
171              padding: const EdgeInsets.all(4.0),
172              child: Column(
173                children: <Widget>[
174                  Row(
175                    children: <Widget>[
176                      Checkbox(
177                        value: _scaleEnabled,
178                        onChanged: (bool value) { setState(() { _scaleEnabled = value; }); },
179                      ),
180                      const Text('Scale'),
181                    ],
182                  ),
183                  Row(
184                    children: <Widget>[
185                      Checkbox(
186                        value: _tapEnabled,
187                        onChanged: (bool value) { setState(() { _tapEnabled = value; }); },
188                      ),
189                      const Text('Tap'),
190                    ],
191                  ),
192                  Row(
193                    children: <Widget>[
194                      Checkbox(
195                        value: _doubleTapEnabled,
196                        onChanged: (bool value) { setState(() { _doubleTapEnabled = value; }); },
197                      ),
198                      const Text('Double Tap'),
199                    ],
200                  ),
201                  Row(
202                    children: <Widget>[
203                      Checkbox(
204                        value: _longPressEnabled,
205                        onChanged: (bool value) { setState(() { _longPressEnabled = value; }); },
206                      ),
207                      const Text('Long Press'),
208                    ],
209                  ),
210                ],
211                crossAxisAlignment: CrossAxisAlignment.start,
212              ),
213            ),
214          ),
215        ),
216      ],
217    );
218  }
219}
220
221void main() {
222  runApp(MaterialApp(
223    theme: ThemeData.dark(),
224    home: Scaffold(
225      appBar: AppBar(title: const Text('Gestures Demo')),
226      body: GestureDemo(),
227    ),
228  ));
229}
230