// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; class _GesturePainter extends CustomPainter { const _GesturePainter({ this.zoom, this.offset, this.swatch, this.forward, this.scaleEnabled, this.tapEnabled, this.doubleTapEnabled, this.longPressEnabled }); final double zoom; final Offset offset; final MaterialColor swatch; final bool forward; final bool scaleEnabled; final bool tapEnabled; final bool doubleTapEnabled; final bool longPressEnabled; @override void paint(Canvas canvas, Size size) { final Point center = (size.center(Point.origin).toOffset() * zoom + offset).toPoint(); final double radius = size.width / 2.0 * zoom; final Gradient gradient = new RadialGradient( colors: forward ? <Color>[swatch.shade50, swatch.shade900] : <Color>[swatch.shade900, swatch.shade50] ); final Paint paint = new Paint() ..shader = gradient.createShader(new Rect.fromLTWH( center.x - radius, center.y - radius, radius * 2.0, radius * 2.0 )); canvas.drawCircle(center, radius, paint); } @override bool shouldRepaint(_GesturePainter oldPainter) { return oldPainter.zoom != zoom || oldPainter.offset != offset || oldPainter.swatch != swatch || oldPainter.forward != forward || oldPainter.scaleEnabled != scaleEnabled || oldPainter.tapEnabled != tapEnabled || oldPainter.doubleTapEnabled != doubleTapEnabled || oldPainter.longPressEnabled != longPressEnabled; } } class GestureDemo extends StatefulWidget { @override _GestureDemoState createState() => new _GestureDemoState(); } class _GestureDemoState extends State<GestureDemo> { Point _startingFocalPoint; Offset _previousOffset; Offset _offset = Offset.zero; double _previousZoom; double _zoom = 1.0; MaterialColor _swatch = Colors.blue; bool _forward = true; bool _scaleEnabled = true; bool _tapEnabled = true; bool _doubleTapEnabled = true; bool _longPressEnabled = true; void _handleScaleStart(ScaleStartDetails details) { setState(() { _startingFocalPoint = details.focalPoint; _previousOffset = _offset; _previousZoom = _zoom; }); } void _handleScaleUpdate(ScaleUpdateDetails details) { setState(() { _zoom = (_previousZoom * details.scale); // Ensure that item under the focal point stays in the same place despite zooming final Offset normalizedOffset = (_startingFocalPoint.toOffset() - _previousOffset) / _previousZoom; _offset = details.focalPoint.toOffset() - normalizedOffset * _zoom; }); } void _handleScaleReset() { setState(() { _zoom = 1.0; _offset = Offset.zero; }); } void _handleColorChange() { setState(() { if (_swatch == Colors.blueGrey) _swatch = Colors.red; else if (_swatch == Colors.red) _swatch = Colors.pink; else if (_swatch == Colors.pink) _swatch = Colors.purple; else if (_swatch == Colors.purple) _swatch = Colors.deepPurple; else if (_swatch == Colors.deepPurple) _swatch = Colors.indigo; else if (_swatch == Colors.indigo) _swatch = Colors.blue; else if (_swatch == Colors.blue) _swatch = Colors.lightBlue; else if (_swatch == Colors.lightBlue) _swatch = Colors.cyan; else if (_swatch == Colors.teal) _swatch = Colors.green; else if (_swatch == Colors.green) _swatch = Colors.lightGreen; else if (_swatch == Colors.lightGreen) _swatch = Colors.lime; else if (_swatch == Colors.lime) _swatch = Colors.yellow; else if (_swatch == Colors.yellow) _swatch = Colors.amber; else if (_swatch == Colors.amber) _swatch = Colors.orange; else if (_swatch == Colors.orange) _swatch = Colors.deepOrange; else if (_swatch == Colors.deepOrange) _swatch = Colors.brown; else if (_swatch == Colors.brown) _swatch = Colors.grey; else if (_swatch == Colors.grey) _swatch = Colors.blueGrey; }); } void _handleDirectionChange() { setState(() { _forward = !_forward; }); } @override Widget build(BuildContext context) { return new Stack( children: <Widget>[ new GestureDetector( onScaleStart: _scaleEnabled ? _handleScaleStart : null, onScaleUpdate: _scaleEnabled ? _handleScaleUpdate : null, onTap: _tapEnabled ? _handleColorChange : null, onDoubleTap: _doubleTapEnabled ? _handleScaleReset : null, onLongPress: _longPressEnabled ? _handleDirectionChange : null, child: new CustomPaint( painter: new _GesturePainter( zoom: _zoom, offset: _offset, swatch: _swatch, forward: _forward, scaleEnabled: _scaleEnabled, tapEnabled: _tapEnabled, doubleTapEnabled: _doubleTapEnabled, longPressEnabled: _longPressEnabled ) ) ), new Positioned( bottom: 0.0, left: 0.0, child: new Card( child: new Container( padding: const EdgeInsets.all(4.0), child: new Column( children: <Widget>[ new Row( children: <Widget>[ new Checkbox( value: _scaleEnabled, onChanged: (bool value) { setState(() { _scaleEnabled = value; }); } ), new Text('Scale'), ] ), new Row( children: <Widget>[ new Checkbox( value: _tapEnabled, onChanged: (bool value) { setState(() { _tapEnabled = value; }); } ), new Text('Tap'), ] ), new Row( children: <Widget>[ new Checkbox( value: _doubleTapEnabled, onChanged: (bool value) { setState(() { _doubleTapEnabled = value; }); } ), new Text('Double Tap'), ] ), new Row( children: <Widget>[ new Checkbox( value: _longPressEnabled, onChanged: (bool value) { setState(() { _longPressEnabled = value; }); } ), new Text('Long Press'), ] ), ], crossAxisAlignment: CrossAxisAlignment.start ) ) ) ), ] ); } } void main() { runApp(new MaterialApp( theme: new ThemeData.dark(), home: new Scaffold( appBar: new AppBar(title: new Text('Gestures Demo')), body: new GestureDemo() ) )); }