// 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/animation.dart'; import 'package:flutter/gestures.dart'; import 'binding.dart'; import 'box.dart'; import 'object.dart'; import 'proxy_box.dart'; typedef void ValueChanged<T>(T value); const Duration _kToggleDuration = const Duration(milliseconds: 200); // RenderToggleable is a base class for material style toggleable controls with // toggle animations. It handles storing the current value, dispatching // ValueChanged on a tap gesture and driving a changed animation. Subclasses are // responsible for painting. abstract class RenderToggleable extends RenderConstrainedBox { RenderToggleable({ bool value, Size size, this.onChanged }) : _value = value, super(additionalConstraints: new BoxConstraints.tight(size)) { _performance = new ValuePerformance<double>( variable: new AnimatedValue<double>(0.0, end: 1.0, curve: Curves.easeIn, reverseCurve: Curves.easeOut), duration: _kToggleDuration, progress: _value ? 1.0 : 0.0 )..addListener(markNeedsPaint); } bool get value => _value; bool _value; void set value(bool value) { if (value == _value) return; _value = value; performance.play(value ? AnimationDirection.forward : AnimationDirection.reverse); } ValueChanged<bool> onChanged; ValuePerformance<double> get performance => _performance; ValuePerformance<double> _performance; double get position => _performance.value; TapGestureRecognizer _tap; void attach() { super.attach(); _tap = new TapGestureRecognizer( router: FlutterBinding.instance.pointerRouter, onTap: _handleTap ); } void detach() { _tap.dispose(); _tap = null; super.detach(); } void handleEvent(InputEvent event, BoxHitTestEntry entry) { if (event.type == 'pointerdown' && onChanged != null) _tap.addPointer(event); } void _handleTap() { if (onChanged != null) onChanged(!_value); } bool hitTestSelf(Point position) => true; }