// 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'; import 'package:flutter/rendering.dart'; class ScaleApp extends StatefulComponent { ScaleAppState createState() => new ScaleAppState(); } 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 Map<int, Color> swatch; final bool forward; final bool scaleEnabled; final bool tapEnabled; final bool doubleTapEnabled; final bool longPressEnabled; void paint(PaintingCanvas canvas, Size size) { Point center = (size.center(Point.origin).toOffset() * zoom + offset).toPoint(); double radius = size.width / 2.0 * zoom; Gradient gradient = new RadialGradient( center: center, radius: radius, colors: forward ? <Color>[swatch[50], swatch[900]] : <Color>[swatch[900], swatch[50]] ); Paint paint = new Paint() ..shader = gradient.createShader(); canvas.drawCircle(center, radius, paint); } 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 ScaleAppState extends State<ScaleApp> { Point _startingFocalPoint; Offset _previousOffset; Offset _offset = Offset.zero; double _previousZoom; double _zoom = 1.0; Map<int, Color> _swatch = Colors.blue; bool _forward = true; bool _scaleEnabled = true; bool _tapEnabled = true; bool _doubleTapEnabled = true; bool _longPressEnabled = true; void _handleScaleStart(Point focalPoint) { setState(() { _startingFocalPoint = focalPoint; _previousOffset = _offset; _previousZoom = _zoom; }); } void _handleScaleUpdate(double scale, Point focalPoint) { setState(() { _zoom = (_previousZoom * scale); // Ensure that item under the focal point stays in the same place despite zooming Offset normalizedOffset = (_startingFocalPoint.toOffset() - _previousOffset) / _previousZoom; _offset = focalPoint.toOffset() - normalizedOffset * _zoom; }); } void _handleScaleReset() { setState(() { _zoom = 1.0; _offset = Offset.zero; }); } void _handleColorChange() { setState(() { switch (_swatch) { case Colors.blueGrey: _swatch = Colors.red; break; case Colors.red: _swatch = Colors.pink; break; case Colors.pink: _swatch = Colors.purple; break; case Colors.purple: _swatch = Colors.deepPurple; break; case Colors.deepPurple: _swatch = Colors.indigo; break; case Colors.indigo: _swatch = Colors.blue; break; case Colors.blue: _swatch = Colors.lightBlue; break; case Colors.lightBlue: _swatch = Colors.cyan; break; case Colors.cyan: _swatch = Colors.teal; break; case Colors.teal: _swatch = Colors.green; break; case Colors.green: _swatch = Colors.lightGreen; break; case Colors.lightGreen: _swatch = Colors.lime; break; case Colors.lime: _swatch = Colors.yellow; break; case Colors.yellow: _swatch = Colors.amber; break; case Colors.amber: _swatch = Colors.orange; break; case Colors.orange: _swatch = Colors.deepOrange; break; case Colors.deepOrange: _swatch = Colors.brown; break; case Colors.brown: _swatch = Colors.grey; break; case Colors.grey: _swatch = Colors.blueGrey; break; default: assert(false); } }); } void _handleDirectionChange() { setState(() { _forward = !_forward; }); } Widget build(BuildContext context) { return new Theme( data: new ThemeData.dark(), child: new Scaffold( toolBar: new ToolBar( center: new Text('Gestures Demo')), body: new Stack([ 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: new EdgeDims.all(4.0), child: new Column([ new Row([ new Checkbox( value: _scaleEnabled, onChanged: (bool value) { setState(() { _scaleEnabled = value; }); } ), new Text('Scale'), ]), new Row([ new Checkbox( value: _tapEnabled, onChanged: (bool value) { setState(() { _tapEnabled = value; }); } ), new Text('Tap'), ]), new Row([ new Checkbox( value: _doubleTapEnabled, onChanged: (bool value) { setState(() { _doubleTapEnabled = value; }); } ), new Text('Double Tap'), ]), new Row([ new Checkbox( value: _longPressEnabled, onChanged: (bool value) { setState(() { _longPressEnabled = value; }); } ), new Text('Long Press'), ]), ], alignItems: FlexAlignItems.start ) ) ) ), ]) ) ); } } void main() => runApp(new ScaleApp());