Commit 7782a115 authored by Hans Muller's avatar Hans Muller

Adds PageableList, other scrolling related changes and fixes

- PageableList extends ScrollableList
One fixed width or height item is visible and centered at a
time. Fling and drag gestures scroll to the next/previous item.

- Scrollable.scrollTo(), Scrollable.scrollBy(), ensureWidgetIsVisible() API changed
The named animation parameter for these methods was replaced by
duration and curve. All of the methods now return a Future. The Future
completes when the scroll does.

This change eliminates the need for Scrollable to temporarily take ownership
of a ValueAnimation object (see #645).

- Using Future.then() instead of an AnimationPerformance status listener
In ensure_visible.dart _handleTap() uses ensureWidgetIsVisible() to
center the card roughly as before and then. When the implicit scroll
animation is complete, it changes the centered card's label font. The
change is made when the Future returned by ensureWidgetIsVisible()
completes.

- FixedHeightScrollable's itemHeight parameter is now itemExtent
If scrollDirection is ScrollDirection.vertical (the default) then itemExtent should
be the height of each item; otherwise it should be the width of each item.

Replaced _velocityForFlingGesture() in scrollable.dart with Scrollable._eventVelocity()
The original version clamped pixels/ms against pixels/sec constants. The new version
also deals with scrollDirection.

- Plumbed scrollDirection though FixedHeightScrollable and ScrollableList

Both classes should now support horizontal scrolling.
parent 7786211c
......@@ -177,7 +177,7 @@ class DemoList extends Component {
Widget build() {
return new ScrollableList<SkyDemo>(
items: demos,
itemHeight: kCardHeight,
itemExtent: kCardHeight,
itemBuilder: buildDemo,
padding: kListPadding
);
......
......@@ -19,7 +19,7 @@ class FitnessItemList extends Component {
child: new ScrollableList<FitnessItem>(
padding: const EdgeDims.all(4.0),
items: items,
itemHeight: kFitnessItemHeight,
itemExtent: kFitnessItemHeight,
itemBuilder: (item) => item.toRow(onDismissed: onDismissed)
)
);
......
......@@ -14,7 +14,7 @@ class Stocklist extends Component {
type: MaterialType.canvas,
child: new ScrollableList<Stock>(
items: stocks,
itemHeight: StockRow.kHeight,
itemExtent: StockRow.kHeight,
itemBuilder: (stock) => new StockRow(stock: stock)
)
);
......
......@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/animation/animated_value.dart';
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/base/lerp.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets.dart';
......@@ -23,10 +20,12 @@ class EnsureVisibleApp extends App {
static const TextStyle cardLabelStyle =
const TextStyle(color: colors.white, fontSize: 18.0, fontWeight: bold);
static const TextStyle selectedCardLabelStyle =
const TextStyle(color: white, fontSize: 24.0, fontWeight: bold);
List<CardModel> cardModels;
BlockViewportLayoutState layoutState = new BlockViewportLayoutState();
ScrollListener scrollListener;
ValueAnimation<double> scrollAnimation;
CardModel selectedCardModel;
void initState() {
List<double> cardHeights = <double>[
......@@ -39,15 +38,15 @@ class EnsureVisibleApp extends App {
return new CardModel(i, cardHeights[i], color);
});
scrollAnimation = new ValueAnimation<double>()
..duration = const Duration(milliseconds: 200)
..variable = new AnimatedValue<double>(0.0, curve: ease);
super.initState();
}
EventDisposition handleTap(Widget target) {
ensureWidgetIsVisible(target, animation: scrollAnimation);
EventDisposition handleTap(Widget card, CardModel cardModel) {
ensureWidgetIsVisible(card, duration: const Duration(milliseconds: 200))
.then((_) {
setState(() { selectedCardModel = cardModel; });
});
return EventDisposition.processed;
}
......@@ -55,17 +54,18 @@ class EnsureVisibleApp extends App {
if (index >= cardModels.length)
return null;
CardModel cardModel = cardModels[index];
TextStyle style = (cardModel == selectedCardModel) ? selectedCardLabelStyle : cardLabelStyle;
Widget card = new Card(
color: cardModel.color,
child: new Container(
height: cardModel.height,
padding: const EdgeDims.all(8.0),
child: new Center(child: new Text(cardModel.label, style: cardLabelStyle))
child: new Center(child: new Text(cardModel.label, style: style))
)
);
return new Listener(
key: cardModel.key,
onGestureTap: (_) { return handleTap(card); },
onGestureTap: (_) { return handleTap(card, cardModel); },
child: card
);
}
......
// 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:sky/base/lerp.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/card.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/scrollable.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/widgets/task_description.dart';
class CardModel {
CardModel(this.value, this.size, this.color);
int value;
Size size;
Color color;
String get label => "Card $value";
Key get key => new Key.fromObjectIdentity(this);
}
class TestApp extends App {
static const TextStyle cardLabelStyle =
const TextStyle(color: white, fontSize: 18.0, fontWeight: bold);
List<CardModel> cardModels;
Size pageSize = new Size(200.0, 200.0);
void initState() {
List<Size> cardSizes = [
[100.0, 300.0], [300.0, 100.0], [200.0, 400.0], [400.0, 400.0], [300.0, 400.0],
[100.0, 300.0], [300.0, 100.0], [200.0, 400.0], [400.0, 400.0], [300.0, 400.0],
[100.0, 300.0], [300.0, 100.0], [200.0, 400.0], [400.0, 400.0], [300.0, 400.0]
]
.map((args) => new Size(args[0], args[1]))
.toList();
cardModels = new List.generate(cardSizes.length, (i) {
Color color = lerpColor(Red[300], Blue[900], i / cardSizes.length);
return new CardModel(i, cardSizes[i], color);
});
super.initState();
}
void updatePageSize(Size newSize) {
setState(() {
pageSize = newSize;
});
}
Widget buildCard(CardModel cardModel) {
print("SKY buildCard ${cardModel.label}");
Widget card = new Card(
color: cardModel.color,
child: new Container(
width: cardModel.size.width,
height: cardModel.size.height,
padding: const EdgeDims.all(8.0),
child: new Center(child: new Text(cardModel.label, style: cardLabelStyle))
)
);
return new Container(
key: cardModel.key,
width: pageSize.width,
child: new Center(child: card)
);
}
Widget build() {
Widget list = new PageableList<CardModel>(
items: cardModels,
itemBuilder: buildCard,
scrollDirection: ScrollDirection.horizontal,
itemExtent: pageSize.width
);
return new IconTheme(
data: const IconThemeData(color: IconThemeColor.white),
child: new Theme(
data: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Blue,
accentColor: RedAccent[200]
),
child: new TaskDescription(
label: 'PageableList',
child: new Scaffold(
toolbar: new ToolBar(center: new Text('PageableList Demo')),
body: new SizeObserver(
callback: updatePageSize,
child: new Container(
child: list,
decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatch[50])
)
)
)
)
)
);
}
}
void main() {
runApp(new TestApp());
}
......@@ -767,6 +767,8 @@ abstract class StatefulComponent extends Component {
return super.syncChild(node, oldNode, slot);
}
// Calls function fn immediately and then schedules another build
// for this Component.
void setState(void fn()) {
assert(!_disqualifiedFromEverAppearingAgain);
fn();
......
......@@ -408,16 +408,12 @@ class TabBar extends Scrollable {
Size _tabBarSize;
List<double> _tabWidths;
ValueAnimation<Rect> _indicatorAnimation;
ValueAnimation<double> _scrollAnimation;
void initState() {
super.initState();
_indicatorAnimation = new ValueAnimation<Rect>()
..duration = _kTabBarScroll
..variable = new AnimatedRect(null, curve: ease);
_scrollAnimation = new ValueAnimation<double>()
..duration = _kTabBarScroll
..variable = new AnimatedValue<double>(0.0, curve: ease);
}
void syncFields(TabBar source) {
......@@ -473,7 +469,7 @@ class TabBar extends Scrollable {
if (tabIndex != selectedIndex) {
if (_tabWidths != null) {
if (isScrollable)
scrollTo(_centeredTabScrollOffset(tabIndex), animation: _scrollAnimation);
scrollTo(_centeredTabScrollOffset(tabIndex), duration: _kTabBarScroll);
_startIndicatorAnimation(selectedIndex, tabIndex);
}
if (onChanged != null)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment