mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #1476 from abarth/ink_well_gestures
RenderInkWell should use gestures
This commit is contained in:
commit
44dbe3c77d
@ -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<SkyDemo> demos = [
|
||||
new SkyDemo(
|
||||
List<FlutterDemo> demos = [
|
||||
new FlutterDemo(
|
||||
name: 'Stocks',
|
||||
href: '../../stocks/lib/main.dart',
|
||||
bundle: 'stocks.skyx',
|
||||
@ -74,7 +74,7 @@ List<SkyDemo> demos = [
|
||||
)
|
||||
)
|
||||
),
|
||||
new SkyDemo(
|
||||
new FlutterDemo(
|
||||
name: 'Asteroids',
|
||||
href: '../../game/lib/main.dart',
|
||||
bundle: 'game.skyx',
|
||||
@ -87,7 +87,7 @@ List<SkyDemo> demos = [
|
||||
)
|
||||
)
|
||||
),
|
||||
new SkyDemo(
|
||||
new FlutterDemo(
|
||||
name: 'Fitness',
|
||||
href: '../../fitness/lib/main.dart',
|
||||
bundle: 'fitness.skyx',
|
||||
@ -97,7 +97,7 @@ List<SkyDemo> 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<SkyDemo> 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<SkyDemo> 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<SkyDemo> 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<SkyDemo>(
|
||||
return new ScrollableList<FlutterDemo>(
|
||||
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()
|
||||
|
||||
@ -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)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@ -65,12 +65,13 @@ class MealFragmentState extends State<MealFragment> {
|
||||
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')
|
||||
)
|
||||
)]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -136,12 +136,13 @@ class MeasurementFragmentState extends State<MeasurementFragment> {
|
||||
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')
|
||||
)
|
||||
)]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
)
|
||||
])
|
||||
)
|
||||
)
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||
);
|
||||
}
|
||||
|
||||
void detatch() {
|
||||
void detach() {
|
||||
_tap.dispose();
|
||||
_tap = null;
|
||||
super.detach();
|
||||
|
||||
@ -375,22 +375,20 @@ class YearPickerState extends ScrollableWidgetListState<YearPicker> {
|
||||
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)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@ -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<Widget> 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) {
|
||||
|
||||
@ -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<DrawerItem> {
|
||||
)
|
||||
);
|
||||
|
||||
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)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<FloatingActionButton> {
|
||||
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
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -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<GestureDetector> {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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<double>(
|
||||
_kSplashInitialSize, end: _targetRadius, curve: easeOut);
|
||||
@ -33,11 +35,12 @@ class InkSplash {
|
||||
_performance = new ValueAnimation<double>(
|
||||
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<double> _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<InkSplash> _splashes = new List<InkSplash>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<T extends MaterialButton> extends ButtonState<T> {
|
||||
@ -37,17 +37,17 @@ abstract class MaterialButtonState<T extends MaterialButton> 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
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@ -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<PopupMenu> {
|
||||
children.add(new FadeTransition(
|
||||
performance: config.performance,
|
||||
opacity: new AnimatedValue<double>(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]
|
||||
))
|
||||
|
||||
@ -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
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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<TabBar> {
|
||||
.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<TabBar> {
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user