Adam Barth 9bc64540c5 Improve hit testing
Now a RenderBox is considered hit if one of its children are hit or it itself
decides that it's hit. In particular, empty space inside a flex won't be hit
because none of the children are located there and a RenderFlex doesn't
consider itself hittable.

Fixes #53
Fixes #1221
2015-11-04 16:51:19 -08:00

79 lines
2.1 KiB
Dart

// 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;
}