Skip to content

Commit

Permalink
Merge pull request #70 from collinjackson/navigator
Browse files Browse the repository at this point in the history
Support for settings fly-in animation

R=abarth
  • Loading branch information
collinjackson committed Jul 17, 2015
2 parents 770dae4 + 10d5192 commit 881addf
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 23 deletions.
28 changes: 17 additions & 11 deletions sky/sdk/example/widgets/navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ List<Route> routes = [
new Route(
name: 'home',
builder: (navigator, route) => new Container(
padding: const EdgeDims.all(20.0),
padding: const EdgeDims.all(30.0),
decoration: new BoxDecoration(backgroundColor: const Color(0xFFCCCCCC)),
child: new Block([
child: new Flex([
new Text("You are at home"),
new RaisedButton(
child: new Text('GO SHOPPING'),
Expand All @@ -21,16 +21,18 @@ List<Route> routes = [
new RaisedButton(
child: new Text('START ADVENTURE'),
onPressed: () => navigator.pushNamed('adventure')
)
])
)],
direction: FlexDirection.vertical,
justifyContent: FlexJustifyContent.center
)
)
),
new Route(
name: 'shopping',
builder: (navigator, route) => new Container(
padding: const EdgeDims.all(20.0),
decoration: new BoxDecoration(backgroundColor: const Color(0xFFBF5FFF)),
child: new Block([
child: new Flex([
new Text("Village Shop"),
new RaisedButton(
child: new Text('RETURN HOME'),
Expand All @@ -39,22 +41,26 @@ List<Route> routes = [
new RaisedButton(
child: new Text('GO TO DUNGEON'),
onPressed: () => navigator.push(routes[2])
)
])
)],
direction: FlexDirection.vertical,
justifyContent: FlexJustifyContent.center
)
)
),
new Route(
name: 'adventure',
builder: (navigator, route) => new Container(
padding: const EdgeDims.all(20.0),
decoration: new BoxDecoration(backgroundColor: const Color(0xFFDC143C)),
child: new Block([
child: new Flex([
new Text("Monster's Lair"),
new RaisedButton(
child: new Text('NO WAIT! GO BACK!'),
child: new Text('RUN!!!'),
onPressed: () => navigator.pop()
)
])
)],
direction: FlexDirection.vertical,
justifyContent: FlexJustifyContent.center
)
)
)
];
Expand Down
147 changes: 135 additions & 12 deletions sky/sdk/lib/widgets/navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/widgets/animated_component.dart';
import 'package:sky/widgets/animation_builder.dart';
import 'package:sky/widgets/basic.dart';
import 'package:vector_math/vector_math.dart';

typedef Widget Builder(Navigator navigator, RouteBase route);

Expand All @@ -27,31 +32,125 @@ class RouteState extends RouteBase {
RouteBase route;
Function callback;

Widget build(Navigator navigator, _) => route.build(navigator, this);
Widget build(Navigator navigator, RouteBase route) => null;

void popState() {
if (callback != null)
callback(this);
}
}

// TODO(jackson): Refactor this into its own file
// and support multiple transition types
const Duration _kTransitionDuration = const Duration(milliseconds: 200);
const Point _kTransitionStartPoint = const Point(0.0, 100.0);
enum TransitionDirection { forward, reverse }
class Transition extends AnimatedComponent {
Transition({
String key,
this.content,
this.direction,
this.onDismissed,
this.interactive
}) : super(key: key);
Widget content;
TransitionDirection direction;
bool interactive;
Function onDismissed;

AnimatedType<Point> _position;
AnimatedType<double> _opacity;
AnimationPerformance _performance;

void initState() {
_position = new AnimatedType<Point>(
_kTransitionStartPoint,
end: Point.origin,
curve: easeOut
);
_opacity = new AnimatedType<double>(0.0, end: 1.0)
..curve = easeOut;
_performance = new AnimationPerformance()
..duration = _kTransitionDuration
..variable = new AnimatedList([_position, _opacity])
..addListener(_checkDismissed);
if (direction == TransitionDirection.reverse)
_performance.progress = 1.0;
watch(_performance);
_start();
}

void _start() {
_dismissed = false;
switch (direction) {
case TransitionDirection.forward:
_performance.play();
break;
case TransitionDirection.reverse:
_performance.reverse();
break;
}
}

void syncFields(Transition source) {
content = source.content;
if (direction != source.direction) {
direction = source.direction;
_start();
}
interactive = source.interactive;
onDismissed = source.onDismissed;
super.syncFields(source);
}

bool _dismissed = false;
void _checkDismissed() {
if (!_dismissed &&
direction == TransitionDirection.reverse &&
_performance.isDismissed) {
if (onDismissed != null)
onDismissed();
_dismissed = true;
}
}

Widget build() {
Matrix4 transform = new Matrix4.identity()
..translate(_position.value.x, _position.value.y);
// TODO(jackson): Hit testing should ignore transform
// TODO(jackson): Block input unless content is interactive
return new Transform(
transform: transform,
child: new Opacity(
opacity: _opacity.value,
child: content
)
);
}
}

class HistoryEntry {
HistoryEntry(this.route);
final RouteBase route;
// TODO(jackson): Keep track of the requested transition
}

class NavigationState {

NavigationState(List<Route> routes) {
for (Route route in routes) {
if (route.name != null)
namedRoutes[route.name] = route;
}
history.add(routes[0]);
history.add(new HistoryEntry(routes[0]));
}

List<RouteBase> history = new List<RouteBase>();
List<HistoryEntry> history = new List<HistoryEntry>();
int historyIndex = 0;
Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>();

RouteBase get currentRoute => history[historyIndex];
RouteBase get currentRoute => history[historyIndex].route;
bool hasPrevious() => historyIndex > 0;
bool hasNext() => history.length > historyIndex + 1;

void pushNamed(String name) {
Route route = namedRoutes[name];
Expand All @@ -60,16 +159,15 @@ class NavigationState {
}

void push(RouteBase route) {
// Discard future history
history.removeRange(historyIndex + 1, history.length);
historyIndex = history.length;
history.add(route);
HistoryEntry historyEntry = new HistoryEntry(route);
history.insert(historyIndex + 1, historyEntry);
historyIndex++;
}

void pop() {
if (historyIndex > 0) {
history[historyIndex].popState();
history.removeLast();
HistoryEntry entry = history[historyIndex];
entry.route.popState();
historyIndex--;
}
}
Expand Down Expand Up @@ -115,6 +213,31 @@ class Navigator extends StatefulComponent {
}

Widget build() {
return state.currentRoute.build(this, state.currentRoute);
List<Widget> visibleRoutes = new List<Widget>();
for (int i = 0; i < state.history.length; i++) {
// TODO(jackson): Avoid building routes that are not visible
HistoryEntry historyEntry = state.history[i];
Widget content = historyEntry.route.build(this, historyEntry.route);
if (i == 0) {
visibleRoutes.add(content);
continue;
}
if (content == null)
continue;
String key = historyEntry.route.key;
Transition transition = new Transition(
key: key,
content: content,
direction: (i <= state.historyIndex) ? TransitionDirection.forward : TransitionDirection.reverse,
interactive: (i == state.historyIndex),
onDismissed: () {
setState(() {
state.history.remove(historyEntry);
});
}
);
visibleRoutes.add(transition);
}
return new Stack(visibleRoutes);
}
}

0 comments on commit 881addf

Please sign in to comment.