diff --git a/examples/demo_launcher/lib/main.dart b/examples/demo_launcher/lib/main.dart index 3a80555ccc1..4fc089c33d0 100644 --- a/examples/demo_launcher/lib/main.dart +++ b/examples/demo_launcher/lib/main.dart @@ -42,8 +42,8 @@ void launch(String relativeUrl, String bundle) { activity.startActivity(intent); } -class SkyDemo { - SkyDemo({ +class FlutterDemo { + FlutterDemo({ name, this.href, this.bundle, @@ -60,8 +60,8 @@ class SkyDemo { final BoxDecoration decoration; } -List demos = [ - new SkyDemo( +List demos = [ + new FlutterDemo( name: 'Stocks', href: '../../stocks/lib/main.dart', bundle: 'stocks.skyx', @@ -74,7 +74,7 @@ List demos = [ ) ) ), - new SkyDemo( + new FlutterDemo( name: 'Asteroids', href: '../../game/lib/main.dart', bundle: 'game.skyx', @@ -87,7 +87,7 @@ List demos = [ ) ) ), - new SkyDemo( + new FlutterDemo( name: 'Fitness', href: '../../fitness/lib/main.dart', bundle: 'fitness.skyx', @@ -97,7 +97,7 @@ List demos = [ backgroundColor: Colors.indigo[500] ) ), - new SkyDemo( + new FlutterDemo( name: 'Swipe Away', href: '../../widgets/card_collection.dart', bundle: 'cards.skyx', @@ -107,7 +107,7 @@ List demos = [ backgroundColor: Colors.redAccent[200] ) ), - new SkyDemo( + new FlutterDemo( name: 'Interactive Text', href: '../../rendering/interactive_flex.dart', bundle: 'interactive_flex.skyx', @@ -120,7 +120,7 @@ List demos = [ // new SkyDemo( // 'Touch Demo', '../../rendering/touch_demo.dart', 'Simple example showing handling of touch events at a low level'), - new SkyDemo( + new FlutterDemo( name: 'Minedigger Game', href: '../../mine_digger/lib/main.dart', bundle: 'mine_digger.skyx', @@ -138,44 +138,47 @@ List demos = [ const double kCardHeight = 120.0; const EdgeDims kListPadding = const EdgeDims.all(4.0); -class DemoList extends StatelessComponent { - Widget buildCardContents(SkyDemo demo) { - return new Container( - decoration: demo.decoration, - child: new InkWell( - child: new Container( - margin: const EdgeDims.only(top: 24.0, left: 24.0), - child: new Column([ - new Text(demo.name, style: demo.textTheme.title), - new Flexible( - child: new Text(demo.description, style: demo.textTheme.subhead) - ) - ], - alignItems: FlexAlignItems.start +class DemoCard extends StatelessComponent { + DemoCard({ Key key, this.demo }) : super(key: key); + + final FlutterDemo demo; + + Widget build(BuildContext context) { + return new Container( + height: kCardHeight, + child: new Card( + child: new Container( + decoration: demo.decoration, + child: new InkWell( + onTap: () => launch(demo.href, demo.bundle), + child: new Container( + margin: const EdgeDims.only(top: 24.0, left: 24.0), + child: new Column([ + new Text(demo.name, style: demo.textTheme.title), + new Flexible( + child: new Text(demo.description, style: demo.textTheme.subhead) + ) + ], + alignItems: FlexAlignItems.start + ) ) ) ) - ); - } - - Widget buildDemo(BuildContext context, SkyDemo demo) { - return new GestureDetector( - key: demo.key, - onTap: () => launch(demo.href, demo.bundle), - child: new Container( - height: kCardHeight, - child: new Card( - child: buildCardContents(demo) - ) ) ); } +} + +class DemoList extends StatelessComponent { + Widget _buildDemoCard(BuildContext context, FlutterDemo demo) { + return new DemoCard(key: demo.key, demo: demo); + } Widget build(BuildContext context) { - return new ScrollableList( + return new ScrollableList( items: demos, itemExtent: kCardHeight, - itemBuilder: buildDemo, + itemBuilder: _buildDemoCard, padding: kListPadding ); } @@ -200,7 +203,7 @@ class DemoHome extends StatelessComponent { void main() { runApp(new App( - title: 'Sky Demos', + title: 'Flutter Demos', theme: _theme, routes: { '/': (NavigatorState navigator, Route route) => new DemoHome() diff --git a/examples/fitness/lib/feed.dart b/examples/fitness/lib/feed.dart index b689531dcf2..a3c0275f7e5 100644 --- a/examples/fitness/lib/feed.dart +++ b/examples/fitness/lib/feed.dart @@ -33,15 +33,13 @@ class DialogMenuItem extends StatelessComponent { Function onPressed; Widget build(BuildContext context) { - return new GestureDetector( - onTap: onPressed, - child: new Container( - height: 48.0, - child: new InkWell( - child: new Padding( - padding: const EdgeDims.symmetric(horizontal: 16.0), - child: new Row(children) - ) + return new Container( + height: 48.0, + child: new InkWell( + onTap: onPressed, + child: new Padding( + padding: const EdgeDims.symmetric(horizontal: 16.0), + child: new Row(children) ) ) ); diff --git a/examples/fitness/lib/meal.dart b/examples/fitness/lib/meal.dart index 5e65025a5ce..e66fb9f9001 100644 --- a/examples/fitness/lib/meal.dart +++ b/examples/fitness/lib/meal.dart @@ -65,12 +65,13 @@ class MealFragmentState extends State { icon: "navigation/close", onPressed: config.navigator.pop), center: new Text('New Meal'), - right: [new InkWell( - child: new GestureDetector( + right: [ + // TODO(abarth): Should this be a FlatButton? + new InkWell( onTap: _handleSave, child: new Text('SAVE') ) - )] + ] ); } diff --git a/examples/fitness/lib/measurement.dart b/examples/fitness/lib/measurement.dart index 573228656e8..695d82a4c63 100644 --- a/examples/fitness/lib/measurement.dart +++ b/examples/fitness/lib/measurement.dart @@ -136,12 +136,13 @@ class MeasurementFragmentState extends State { icon: "navigation/close", onPressed: config.navigator.pop), center: new Text('New Measurement'), - right: [new InkWell( - child: new GestureDetector( + right: [ + // TODO(abarth): Should this be a FlatButton? + new InkWell( onTap: _handleSave, child: new Text('SAVE') ) - )] + ] ); } diff --git a/examples/stocks/lib/stock_row.dart b/examples/stocks/lib/stock_row.dart index bc522bd9d33..da95327cf15 100644 --- a/examples/stocks/lib/stock_row.dart +++ b/examples/stocks/lib/stock_row.dart @@ -55,52 +55,50 @@ class StockRow extends StatelessComponent { String changeInPrice = "${stock.percentChange.toStringAsFixed(2)}%"; if (stock.percentChange > 0) changeInPrice = "+" + changeInPrice; - return new GestureDetector( + return new InkWell( onTap: _getTapHandler(onPressed), onLongPress: _getLongPressHandler(onLongPressed), - child: new InkWell( - child: new Container( - padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0), - decoration: new BoxDecoration( - border: new Border( - bottom: new BorderSide(color: Theme.of(context).dividerColor) - ) + child: new Container( + padding: const EdgeDims.TRBL(16.0, 16.0, 20.0, 16.0), + decoration: new BoxDecoration( + border: new Border( + bottom: new BorderSide(color: Theme.of(context).dividerColor) + ) + ), + child: new Row([ + new Container( + key: arrowKey, + child: new StockArrow(percentChange: stock.percentChange), + margin: const EdgeDims.only(right: 5.0) ), - child: new Row([ - new Container( - key: arrowKey, - child: new StockArrow(percentChange: stock.percentChange), - margin: const EdgeDims.only(right: 5.0) - ), - new Flexible( - child: new Row([ - new Flexible( - flex: 2, - child: new Text( - stock.symbol, - key: symbolKey - ) - ), - new Flexible( - child: new Text( - lastSale, - style: const TextStyle(textAlign: TextAlign.right), - key: priceKey - ) - ), - new Flexible( - child: new Text( - changeInPrice, - style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right) - ) - ), - ], - alignItems: FlexAlignItems.baseline, - textBaseline: DefaultTextStyle.of(context).textBaseline - ) + new Flexible( + child: new Row([ + new Flexible( + flex: 2, + child: new Text( + stock.symbol, + key: symbolKey + ) + ), + new Flexible( + child: new Text( + lastSale, + style: const TextStyle(textAlign: TextAlign.right), + key: priceKey + ) + ), + new Flexible( + child: new Text( + changeInPrice, + style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right) + ) + ), + ], + alignItems: FlexAlignItems.baseline, + textBaseline: DefaultTextStyle.of(context).textBaseline ) - ]) - ) + ) + ]) ) ); } diff --git a/packages/flutter/lib/src/gestures/tap.dart b/packages/flutter/lib/src/gestures/tap.dart index 8c5683fbdf8..092874c3da8 100644 --- a/packages/flutter/lib/src/gestures/tap.dart +++ b/packages/flutter/lib/src/gestures/tap.dart @@ -14,11 +14,26 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { : super(router: router); GestureTapCallback onTap; + GestureTapCallback onTapDown; + GestureTapCallback onTapCancel; void handlePrimaryPointer(sky.PointerEvent event) { - if (event.type == 'pointerup') { + if (event.type == 'pointerdown') { + if (onTapDown != null) + onTapDown(); + } else if (event.type == 'pointerup') { resolve(GestureDisposition.accepted); - onTap(); + if (onTap != null) + onTap(); + } + } + + void rejectGesture(int pointer) { + super.rejectGesture(pointer); + if (pointer == primaryPointer) { + assert(state == GestureRecognizerState.defunct); + if (onTapCancel != null) + onTapCancel(); } } } diff --git a/packages/flutter/lib/src/rendering/toggleable.dart b/packages/flutter/lib/src/rendering/toggleable.dart index ad9d7bc1321..1a2bbae9ed4 100644 --- a/packages/flutter/lib/src/rendering/toggleable.dart +++ b/packages/flutter/lib/src/rendering/toggleable.dart @@ -51,7 +51,7 @@ abstract class RenderToggleable extends RenderConstrainedBox { ); } - void detatch() { + void detach() { _tap.dispose(); _tap = null; super.detach(); diff --git a/packages/flutter/lib/src/widgets/date_picker.dart b/packages/flutter/lib/src/widgets/date_picker.dart index ed3a91c8b7a..5773c0a2645 100644 --- a/packages/flutter/lib/src/widgets/date_picker.dart +++ b/packages/flutter/lib/src/widgets/date_picker.dart @@ -375,22 +375,20 @@ class YearPickerState extends ScrollableWidgetListState { for(int i = start; i < start + count; i++) { int year = config.firstDate.year + i; String label = year.toString(); - Widget item = new GestureDetector( + Widget item = new InkWell( key: new Key(label), onTap: () { DateTime result = new DateTime(year, config.selectedDate.month, config.selectedDate.day); config.onChanged(result); }, - child: new InkWell( - child: new Container( - height: config.itemExtent, - decoration: year == config.selectedDate.year ? new BoxDecoration( - backgroundColor: Theme.of(context).primarySwatch[100], - shape: Shape.circle - ) : null, - child: new Center( - child: new Text(label, style: style) - ) + child: new Container( + height: config.itemExtent, + decoration: year == config.selectedDate.year ? new BoxDecoration( + backgroundColor: Theme.of(context).primarySwatch[100], + shape: Shape.circle + ) : null, + child: new Center( + child: new Text(label, style: style) ) ) ); diff --git a/packages/flutter/lib/src/widgets/dialog.dart b/packages/flutter/lib/src/widgets/dialog.dart index 9b6ca201bf6..ef142d0baa2 100644 --- a/packages/flutter/lib/src/widgets/dialog.dart +++ b/packages/flutter/lib/src/widgets/dialog.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'package:sky/animation.dart'; +import 'package:sky/gestures.dart'; import 'package:sky/material.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/focus.dart'; @@ -52,7 +53,7 @@ class Dialog extends StatelessComponent { final List actions; /// An (optional) callback that is called when the dialog is dismissed. - final Function onDismiss; + final GestureTapCallback onDismiss; Color _getColor(BuildContext context) { switch (Theme.of(context).brightness) { diff --git a/packages/flutter/lib/src/widgets/drawer_item.dart b/packages/flutter/lib/src/widgets/drawer_item.dart index e7a609d06a5..2850d9418d8 100644 --- a/packages/flutter/lib/src/widgets/drawer_item.dart +++ b/packages/flutter/lib/src/widgets/drawer_item.dart @@ -10,7 +10,6 @@ import 'package:sky/painting.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/button_state.dart'; import 'package:sky/src/widgets/framework.dart'; -import 'package:sky/src/widgets/gesture_detector.dart'; import 'package:sky/src/widgets/icon.dart'; import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/theme.dart'; @@ -76,14 +75,12 @@ class DrawerItemState extends ButtonState { ) ); - return new GestureDetector( - onTap: config.onPressed, - child: new Container( - height: 48.0, - decoration: new BoxDecoration(backgroundColor: _getBackgroundColor(themeData)), - child: new InkWell( - child: new Row(flexChildren) - ) + return new Container( + height: 48.0, + decoration: new BoxDecoration(backgroundColor: _getBackgroundColor(themeData)), + child: new InkWell( + onTap: config.onPressed, + child: new Row(flexChildren) ) ); } diff --git a/packages/flutter/lib/src/widgets/flat_button.dart b/packages/flutter/lib/src/widgets/flat_button.dart index 501799005c5..02beead3551 100644 --- a/packages/flutter/lib/src/widgets/flat_button.dart +++ b/packages/flutter/lib/src/widgets/flat_button.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:sky/gestures.dart'; import 'package:sky/material.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; @@ -13,7 +14,7 @@ class FlatButton extends MaterialButton { Key key, Widget child, bool enabled: true, - Function onPressed + GestureTapCallback onPressed }) : super(key: key, child: child, enabled: enabled, diff --git a/packages/flutter/lib/src/widgets/floating_action_button.dart b/packages/flutter/lib/src/widgets/floating_action_button.dart index 24f57bdc257..6b7d4b66c3c 100644 --- a/packages/flutter/lib/src/widgets/floating_action_button.dart +++ b/packages/flutter/lib/src/widgets/floating_action_button.dart @@ -6,7 +6,6 @@ import 'package:sky/gestures.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/button_state.dart'; import 'package:sky/src/widgets/framework.dart'; -import 'package:sky/src/widgets/gesture_detector.dart'; import 'package:sky/src/widgets/icon.dart'; import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/material.dart'; @@ -46,17 +45,15 @@ class FloatingActionButtonState extends ButtonState { type: MaterialType.circle, level: highlight ? 3 : 2, child: new ClipOval( - child: new GestureDetector( - onTap: config.onPressed, - child: new Container( - width: _kSize, - height: _kSize, - child: new InkWell( - child: new Center( - child: new IconTheme( - data: new IconThemeData(color: iconThemeColor), - child: config.child - ) + child: new Container( + width: _kSize, + height: _kSize, + child: new InkWell( + onTap: config.onPressed, + child: new Center( + child: new IconTheme( + data: new IconThemeData(color: iconThemeColor), + child: config.child ) ) ) diff --git a/packages/flutter/lib/src/widgets/gesture_detector.dart b/packages/flutter/lib/src/widgets/gesture_detector.dart index a479f5fc3f9..fb3407908b8 100644 --- a/packages/flutter/lib/src/widgets/gesture_detector.dart +++ b/packages/flutter/lib/src/widgets/gesture_detector.dart @@ -14,6 +14,8 @@ class GestureDetector extends StatefulComponent { Key key, this.child, this.onTap, + this.onTapDown, + this.onTapCancel, this.onShowPress, this.onLongPress, this.onVerticalDragStart, @@ -33,6 +35,9 @@ class GestureDetector extends StatefulComponent { final Widget child; final GestureTapCallback onTap; + final GestureTapCallback onTapDown; + final GestureTapCallback onTapCancel; + final GestureShowPressCallback onShowPress; final GestureLongPressCallback onLongPress; @@ -97,11 +102,14 @@ class GestureDetectorState extends State { } void _syncTap() { - if (config.onTap == null) { + if (config.onTap == null && config.onTapDown == null && config.onTapCancel == null) { _tap = _ensureDisposed(_tap); } else { _tap ??= new TapGestureRecognizer(router: _router); - _tap.onTap = config.onTap; + _tap + ..onTap = config.onTap + ..onTapDown = config.onTapDown + ..onTapCancel = config.onTapCancel; } } diff --git a/packages/flutter/lib/src/widgets/icon_button.dart b/packages/flutter/lib/src/widgets/icon_button.dart index fcb42fd3270..662ee5fb52c 100644 --- a/packages/flutter/lib/src/widgets/icon_button.dart +++ b/packages/flutter/lib/src/widgets/icon_button.dart @@ -4,6 +4,7 @@ import 'dart:sky' as sky; +import 'package:sky/gestures.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/icon.dart'; import 'package:sky/src/widgets/framework.dart'; @@ -13,8 +14,8 @@ class IconButton extends StatelessComponent { const IconButton({ Key key, this.icon, this.onPressed, this.color }) : super(key: key); final String icon; - final Function onPressed; final Color color; + final GestureTapCallback onPressed; Widget build(BuildContext context) { Widget child = new Icon(type: icon, size: 24); diff --git a/packages/flutter/lib/src/widgets/ink_well.dart b/packages/flutter/lib/src/widgets/ink_well.dart index 4e44e0517be..a0f36726d13 100644 --- a/packages/flutter/lib/src/widgets/ink_well.dart +++ b/packages/flutter/lib/src/widgets/ink_well.dart @@ -2,16 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; import 'dart:math' as math; import 'dart:sky' as sky; import 'package:sky/animation.dart'; +import 'package:sky/gestures.dart'; import 'package:sky/rendering.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; const int _kSplashInitialOpacity = 0x30; -const double _kSplashCancelledVelocity = 0.7; +const double _kSplashCanceledVelocity = 0.7; const double _kSplashConfirmedVelocity = 0.7; const double _kSplashInitialSize = 0.0; const double _kSplashUnconfirmedVelocity = 0.2; @@ -25,7 +27,7 @@ double _getSplashTargetSize(Size bounds, Point position) { } class InkSplash { - InkSplash(this.pointer, this.position, this.well) { + InkSplash(this.position, this.well) { _targetRadius = _getSplashTargetSize(well.size, position); _radius = new AnimatedValue( _kSplashInitialSize, end: _targetRadius, curve: easeOut); @@ -33,11 +35,12 @@ class InkSplash { _performance = new ValueAnimation( variable: _radius, duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor()) - )..addListener(_handleRadiusChange) - ..play(); + )..addListener(_handleRadiusChange); + + // Wait kTapTimeout to avoid creating tiny splashes during scrolls. + _startTimer = new Timer(kTapTimeout, _play); } - final int pointer; final Point position; final RenderInkWell well; @@ -45,20 +48,39 @@ class InkSplash { double _pinnedRadius; AnimatedValue _radius; AnimationPerformance _performance; + Timer _startTimer; + + bool _cancelStartTimer() { + if (_startTimer != null) { + _startTimer.cancel(); + _startTimer = null; + return true; + } + return false; + } + + void _play() { + _cancelStartTimer(); + _performance.play(); + } void _updateVelocity(double velocity) { int duration = (_targetRadius / velocity).floor(); - _performance - ..duration = new Duration(milliseconds: duration) - ..play(); + _performance.duration = new Duration(milliseconds: duration); + _play(); } void confirm() { + if (_cancelStartTimer()) + return; _updateVelocity(_kSplashConfirmedVelocity); + _pinnedRadius = null; } void cancel() { - _updateVelocity(_kSplashCancelledVelocity); + if (_cancelStartTimer()) + return; + _updateVelocity(_kSplashCanceledVelocity); _pinnedRadius = _radius.value; } @@ -77,38 +99,95 @@ class InkSplash { } class RenderInkWell extends RenderProxyBox { - RenderInkWell({ RenderBox child }) : super(child); + RenderInkWell({ + RenderBox child, + GestureTapCallback onTap, + GestureLongPressCallback onLongPress + }) : super(child) { + this.onTap = onTap; + this.onLongPress = onLongPress; + } + + GestureTapCallback get onTap => _onTap; + GestureTapCallback _onTap; + void set onTap (GestureTapCallback value) { + _onTap = value; + _syncTapRecognizer(); + } + + GestureTapCallback get onLongPress => _onLongPress; + GestureTapCallback _onLongPress; + void set onLongPress (GestureTapCallback value) { + _onLongPress = value; + _syncLongPressRecognizer(); + } final List _splashes = new List(); + TapGestureRecognizer _tap; + LongPressGestureRecognizer _longPress; + void handleEvent(sky.Event event, BoxHitTestEntry entry) { - // TODO(abarth): We should trigger these effects based on gestures. - // https://github.com/flutter/engine/issues/1271 - if (event is sky.PointerEvent) { - switch (event.type) { - case 'pointerdown': - _startSplash(event.pointer, entry.localPosition); - break; - case 'pointerup': - _confirmSplash(event.pointer); - break; - } + if (event.type == 'pointerdown' && (_tap != null || _longPress != null)) { + _tap?.addPointer(event); + _longPress?.addPointer(event); + _splashes.add(new InkSplash(entry.localPosition, this)); } } - void _startSplash(int pointer, Point position) { - _splashes.add(new InkSplash(pointer, position, this)); - markNeedsPaint(); + void attach() { + super.attach(); + _syncTapRecognizer(); + _syncLongPressRecognizer(); } - void _forEachSplash(int pointer, Function callback) { - _splashes.where((splash) => splash.pointer == pointer) - .forEach(callback); + void detach() { + _disposeTapRecognizer(); + _disposeLongPressRecognizer(); + super.detach(); } - void _confirmSplash(int pointer) { - _forEachSplash(pointer, (splash) { splash.confirm(); }); - markNeedsPaint(); + void _syncTapRecognizer() { + if (onTap == null) { + _disposeTapRecognizer(); + } else { + _tap ??= new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter) + ..onTap = _handleTap + ..onTapCancel = _handleTapCancel; + } + } + + void _disposeTapRecognizer() { + _tap?.dispose(); + _tap = null; + } + + void _syncLongPressRecognizer() { + if (onLongPress == null) { + _disposeLongPressRecognizer(); + } else { + _longPress ??= new LongPressGestureRecognizer(router: FlutterBinding.instance.pointerRouter) + ..onLongPress = _handleLongPress; + } + } + + void _disposeLongPressRecognizer() { + _longPress?.dispose(); + _longPress = null; + } + + void _handleTap() { + _splashes.last?.confirm(); + onTap(); + } + + void _handleTapCancel() { + _splashes.last?.cancel(); + } + + void _handleLongPress() { + _splashes.last?.confirm(); + onLongPress(); } void paint(PaintingContext context, Offset offset) { @@ -126,7 +205,20 @@ class RenderInkWell extends RenderProxyBox { } class InkWell extends OneChildRenderObjectWidget { - InkWell({ Key key, Widget child }) : super(key: key, child: child); + InkWell({ + Key key, + Widget child, + this.onTap, + this.onLongPress + }) : super(key: key, child: child); - RenderInkWell createRenderObject() => new RenderInkWell(); + final GestureTapCallback onTap; + final GestureLongPressCallback onLongPress; + + RenderInkWell createRenderObject() => new RenderInkWell(onTap: onTap, onLongPress: onLongPress); + + void updateRenderObject(RenderInkWell renderObject, InkWell oldWidget) { + renderObject.onTap = onTap; + renderObject.onLongPress = onLongPress; + } } diff --git a/packages/flutter/lib/src/widgets/material_button.dart b/packages/flutter/lib/src/widgets/material_button.dart index c5dfb0a7be3..b18cc313c12 100644 --- a/packages/flutter/lib/src/widgets/material_button.dart +++ b/packages/flutter/lib/src/widgets/material_button.dart @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:sky/gestures.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/button_state.dart'; import 'package:sky/src/widgets/framework.dart'; -import 'package:sky/src/widgets/gesture_detector.dart'; import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/material.dart'; @@ -22,7 +22,7 @@ abstract class MaterialButton extends StatefulComponent { final Widget child; final bool enabled; - final Function onPressed; + final GestureTapCallback onPressed; } abstract class MaterialButtonState extends ButtonState { @@ -37,17 +37,17 @@ abstract class MaterialButtonState extends ButtonState child: config.child // TODO(ianh): figure out a way to compell the child to have gray text when disabled... ) ); - return new GestureDetector( - onTap: config.enabled ? config.onPressed : null, - child: new Container( - height: 36.0, - constraints: new BoxConstraints(minWidth: 88.0), - margin: new EdgeDims.all(8.0), - child: new Material( - type: MaterialType.button, - child: config.enabled ? new InkWell(child: contents) : contents, - level: level, - color: getColor(context) + return new Container( + height: 36.0, + constraints: new BoxConstraints(minWidth: 88.0), + margin: new EdgeDims.all(8.0), + child: new Material( + type: MaterialType.button, + level: level, + color: getColor(context), + child: new InkWell( + onTap: config.enabled ? config.onPressed : null, + child: contents ) ) ); diff --git a/packages/flutter/lib/src/widgets/popup_menu.dart b/packages/flutter/lib/src/widgets/popup_menu.dart index f66f1007c78..c06e9539c82 100644 --- a/packages/flutter/lib/src/widgets/popup_menu.dart +++ b/packages/flutter/lib/src/widgets/popup_menu.dart @@ -11,7 +11,7 @@ import 'package:sky/painting.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/focus.dart'; import 'package:sky/src/widgets/framework.dart'; -import 'package:sky/src/widgets/gesture_detector.dart'; +import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/navigator.dart'; import 'package:sky/src/widgets/popup_menu_item.dart'; import 'package:sky/src/widgets/scrollable.dart'; @@ -94,7 +94,7 @@ class PopupMenuState extends State { children.add(new FadeTransition( performance: config.performance, opacity: new AnimatedValue(0.0, end: 1.0, interval: new Interval(start, end)), - child: new GestureDetector( + child: new InkWell( onTap: () { config.navigator.pop(config.items[i].value); }, child: config.items[i] )) diff --git a/packages/flutter/lib/src/widgets/popup_menu_item.dart b/packages/flutter/lib/src/widgets/popup_menu_item.dart index 1e44c23c2db..d52d8e26ab3 100644 --- a/packages/flutter/lib/src/widgets/popup_menu_item.dart +++ b/packages/flutter/lib/src/widgets/popup_menu_item.dart @@ -4,7 +4,6 @@ import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; -import 'package:sky/src/widgets/ink_well.dart'; import 'package:sky/src/widgets/theme.dart'; const double _kMenuItemHeight = 48.0; @@ -21,15 +20,13 @@ class PopupMenuItem extends StatelessComponent { final dynamic value; Widget build(BuildContext context) { - return new InkWell( - child: new Container( - height: _kMenuItemHeight, - child: new DefaultTextStyle( - style: Theme.of(context).text.subhead, - child: new Baseline( - baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom, - child: child - ) + return new Container( + height: _kMenuItemHeight, + child: new DefaultTextStyle( + style: Theme.of(context).text.subhead, + child: new Baseline( + baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom, + child: child ) ) ); diff --git a/packages/flutter/lib/src/widgets/raised_button.dart b/packages/flutter/lib/src/widgets/raised_button.dart index bf666f27830..22c596511c2 100644 --- a/packages/flutter/lib/src/widgets/raised_button.dart +++ b/packages/flutter/lib/src/widgets/raised_button.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:sky/gestures.dart'; import 'package:sky/material.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; @@ -13,7 +14,7 @@ class RaisedButton extends MaterialButton { Key key, Widget child, bool enabled: true, - Function onPressed + GestureTapCallback onPressed }) : super(key: key, child: child, enabled: enabled, diff --git a/packages/flutter/lib/src/widgets/snack_bar.dart b/packages/flutter/lib/src/widgets/snack_bar.dart index 82ff38feb3f..179e8320ce3 100644 --- a/packages/flutter/lib/src/widgets/snack_bar.dart +++ b/packages/flutter/lib/src/widgets/snack_bar.dart @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'package:sky/animation.dart'; -import 'package:sky/painting.dart'; +import 'package:sky/gestures.dart'; import 'package:sky/material.dart'; +import 'package:sky/painting.dart'; import 'package:sky/src/widgets/animated_component.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; @@ -28,7 +28,7 @@ class SnackBarAction extends StatelessComponent { } final String label; - final Function onPressed; + final GestureTapCallback onPressed; Widget build(BuildContext) { return new GestureDetector( diff --git a/packages/flutter/lib/src/widgets/tabs.dart b/packages/flutter/lib/src/widgets/tabs.dart index d65957c4333..c00bc8ba6fc 100644 --- a/packages/flutter/lib/src/widgets/tabs.dart +++ b/packages/flutter/lib/src/widgets/tabs.dart @@ -7,9 +7,10 @@ import 'dart:sky' as sky; import 'package:newton/newton.dart'; import 'package:sky/animation.dart'; +import 'package:sky/gestures.dart'; +import 'package:sky/material.dart'; import 'package:sky/painting.dart'; import 'package:sky/rendering.dart'; -import 'package:sky/material.dart'; import 'package:sky/src/widgets/basic.dart'; import 'package:sky/src/widgets/framework.dart'; import 'package:sky/src/widgets/gesture_detector.dart'; @@ -307,6 +308,7 @@ class TabLabel { class Tab extends StatelessComponent { Tab({ Key key, + this.onSelected, this.label, this.color, this.selected: false, @@ -315,6 +317,7 @@ class Tab extends StatelessComponent { assert(label.text != null || label.icon != null); } + final GestureTapCallback onSelected; final TabLabel label; final Color color; final bool selected; @@ -359,7 +362,10 @@ class Tab extends StatelessComponent { padding: _kTabLabelPadding ); - return new InkWell(child: centeredLabel); + return new InkWell( + onTap: onSelected, + child: centeredLabel + ); } } @@ -458,7 +464,7 @@ class TabBarState extends ScrollableState { .clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset); } - void _handleTap(int tabIndex) { + void _handleTabSelected(int tabIndex) { if (tabIndex != config.selectedIndex) { if (_tabWidths != null) { if (config.isScrollable) @@ -471,14 +477,12 @@ class TabBarState extends ScrollableState { } Widget _toTab(TabLabel label, int tabIndex, Color color, Color selectedColor) { - return new GestureDetector( - onTap: () => _handleTap(tabIndex), - child: new Tab( - label: label, - color: color, - selected: tabIndex == config.selectedIndex, - selectedColor: selectedColor - ) + return new Tab( + onSelected: () => _handleTabSelected(tabIndex), + label: label, + color: color, + selected: tabIndex == config.selectedIndex, + selectedColor: selectedColor ); }