Commit 65caad47 authored by Hans Muller's avatar Hans Muller

Enable fling scrolling in TabBar

parent 2c09a982
...@@ -16,11 +16,12 @@ class TabbedNavigatorApp extends App { ...@@ -16,11 +16,12 @@ class TabbedNavigatorApp extends App {
// The index of the selected tab for each of the TabNavigators constructed below. // The index of the selected tab for each of the TabNavigators constructed below.
List<int> selectedIndices = new List<int>.filled(5, 0); List<int> selectedIndices = new List<int>.filled(5, 0);
TabNavigator _buildTabNavigator(int n, List<TabNavigatorView> views, {scrollable: false}) { TabNavigator _buildTabNavigator(int n, List<TabNavigatorView> views, Key key, {isScrollable: false}) {
return new TabNavigator( return new TabNavigator(
key: key,
views: views, views: views,
selectedIndex: selectedIndices[n], selectedIndex: selectedIndices[n],
scrollable: scrollable, isScrollable: isScrollable,
onChanged: (tabIndex) { onChanged: (tabIndex) {
setState(() { selectedIndices[n] = tabIndex; } ); setState(() { selectedIndices[n] = tabIndex; } );
} }
...@@ -41,7 +42,7 @@ class TabbedNavigatorApp extends App { ...@@ -41,7 +42,7 @@ class TabbedNavigatorApp extends App {
builder: () => _buildContent(text) builder: () => _buildContent(text)
); );
}); });
return _buildTabNavigator(n, views.toList()); return _buildTabNavigator(n, views.toList(), new Key('textLabelsTabNavigator'));
} }
TabNavigator _buildIconLabelsTabNavigator(int n) { TabNavigator _buildIconLabelsTabNavigator(int n) {
...@@ -52,7 +53,7 @@ class TabbedNavigatorApp extends App { ...@@ -52,7 +53,7 @@ class TabbedNavigatorApp extends App {
builder: () => _buildContent(icon_name) builder: () => _buildContent(icon_name)
); );
}); });
return _buildTabNavigator(n, views.toList()); return _buildTabNavigator(n, views.toList(), new Key('iconLabelsTabNavigator'));
} }
TabNavigator _buildTextAndIconLabelsTabNavigator(int n) { TabNavigator _buildTextAndIconLabelsTabNavigator(int n) {
...@@ -70,7 +71,7 @@ class TabbedNavigatorApp extends App { ...@@ -70,7 +71,7 @@ class TabbedNavigatorApp extends App {
builder: () => _buildContent("Summary") builder: () => _buildContent("Summary")
) )
]; ];
return _buildTabNavigator(n, views); return _buildTabNavigator(n, views, new Key('textAndIconLabelsTabNavigator'));
} }
TabNavigator _buildScrollableTabNavigator(int n) { TabNavigator _buildScrollableTabNavigator(int n) {
...@@ -80,7 +81,7 @@ class TabbedNavigatorApp extends App { ...@@ -80,7 +81,7 @@ class TabbedNavigatorApp extends App {
"THIS TAB IS PRETTY WIDE TOO", "THIS TAB IS PRETTY WIDE TOO",
"MORE", "MORE",
"TABS", "TABS",
"TO", "TO",
"STRETCH", "STRETCH",
"OUT", "OUT",
"THE", "THE",
...@@ -92,7 +93,7 @@ class TabbedNavigatorApp extends App { ...@@ -92,7 +93,7 @@ class TabbedNavigatorApp extends App {
builder: () => _buildContent(text) builder: () => _buildContent(text)
); );
}); });
return _buildTabNavigator(n, views.toList(), scrollable: true); return _buildTabNavigator(n, views.toList(), new Key('scrollableTabNavigator'), isScrollable: true);
} }
...@@ -124,7 +125,7 @@ class TabbedNavigatorApp extends App { ...@@ -124,7 +125,7 @@ class TabbedNavigatorApp extends App {
) )
]; ];
TabNavigator tabNavigator = _buildTabNavigator(4, views); TabNavigator tabNavigator = _buildTabNavigator(4, views, new Key('tabs'));
assert(selectedIndices.length == 5); assert(selectedIndices.length == 5);
ToolBar toolbar = new ToolBar( ToolBar toolbar = new ToolBar(
......
...@@ -60,7 +60,7 @@ class FlingBehavior extends BoundedBehavior { ...@@ -60,7 +60,7 @@ class FlingBehavior extends BoundedBehavior {
: super(contentsSize: contentsSize, containerSize: containerSize); : super(contentsSize: contentsSize, containerSize: containerSize);
Simulation release(double position, double velocity) { Simulation release(double position, double velocity) {
return createDefaultScrollSimulation(position, 0.0, minScrollOffset, maxScrollOffset); return createDefaultScrollSimulation(position, velocity, minScrollOffset, maxScrollOffset);
} }
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:newton/newton.dart';
import 'package:sky/animation/scroll_behavior.dart'; import 'package:sky/animation/scroll_behavior.dart';
import 'package:sky/painting/text_style.dart'; import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart'; import 'package:sky/rendering/box.dart';
...@@ -32,7 +33,7 @@ const double _kRelativeMaxTabWidth = 56.0; ...@@ -32,7 +33,7 @@ const double _kRelativeMaxTabWidth = 56.0;
const EdgeDims _kTabLabelPadding = const EdgeDims.symmetric(horizontal: 12.0); const EdgeDims _kTabLabelPadding = const EdgeDims.symmetric(horizontal: 12.0);
const TextStyle _kTabTextStyle = const TextStyle(textAlign: TextAlign.center); const TextStyle _kTabTextStyle = const TextStyle(textAlign: TextAlign.center);
const int _kTabIconSize = 24; const int _kTabIconSize = 24;
const double _kTabBarScrollFriction = 0.005; const double _kTabBarScrollDrag = 0.025;
class TabBarParentData extends BoxParentData with class TabBarParentData extends BoxParentData with
ContainerParentDataMixin<RenderBox> { } ContainerParentDataMixin<RenderBox> { }
...@@ -79,11 +80,11 @@ class RenderTabBar extends RenderBox with ...@@ -79,11 +80,11 @@ class RenderTabBar extends RenderBox with
} }
} }
bool _scrollable; bool _isScrollable;
bool get scrollable => _scrollable; bool get isScrollable => _isScrollable;
void set scrollable(bool value) { void set isScrollable(bool value) {
if (_scrollable != value) { if (_isScrollable != value) {
_scrollable = value; _isScrollable = value;
markNeedsLayout(); markNeedsLayout();
} }
} }
...@@ -104,7 +105,7 @@ class RenderTabBar extends RenderBox with ...@@ -104,7 +105,7 @@ class RenderTabBar extends RenderBox with
assert(child.parentData is TabBarParentData); assert(child.parentData is TabBarParentData);
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
} }
double width = scrollable ? maxWidth : maxWidth * childCount; double width = isScrollable ? maxWidth : maxWidth * childCount;
return constraints.constrainWidth(width); return constraints.constrainWidth(width);
} }
...@@ -119,7 +120,7 @@ class RenderTabBar extends RenderBox with ...@@ -119,7 +120,7 @@ class RenderTabBar extends RenderBox with
assert(child.parentData is TabBarParentData); assert(child.parentData is TabBarParentData);
child = child.parentData.nextSibling; child = child.parentData.nextSibling;
} }
double width = scrollable ? maxWidth : maxWidth * childCount; double width = isScrollable ? maxWidth : maxWidth * childCount;
return constraints.constrainWidth(width); return constraints.constrainWidth(width);
} }
...@@ -172,10 +173,10 @@ class RenderTabBar extends RenderBox with ...@@ -172,10 +173,10 @@ class RenderTabBar extends RenderBox with
void reportLayoutChangedIfNeeded() { void reportLayoutChangedIfNeeded() {
assert(onLayoutChanged != null); assert(onLayoutChanged != null);
List<double> widths = new List<double>(childCount); List<double> widths = new List<double>(childCount);
if (!scrollable && childCount > 0) { if (!isScrollable && childCount > 0) {
double tabWidth = size.width / childCount; double tabWidth = size.width / childCount;
widths.fillRange(0, widths.length - 1, tabWidth); widths.fillRange(0, widths.length - 1, tabWidth);
} else if (scrollable) { } else if (isScrollable) {
RenderBox child = firstChild; RenderBox child = firstChild;
int childIndex = 0; int childIndex = 0;
while (child != null) { while (child != null) {
...@@ -200,7 +201,7 @@ class RenderTabBar extends RenderBox with ...@@ -200,7 +201,7 @@ class RenderTabBar extends RenderBox with
if (childCount == 0) if (childCount == 0)
return; return;
if (scrollable) if (isScrollable)
layoutScrollableTabs(); layoutScrollableTabs();
else else
layoutFixedWidthTabs(); layoutFixedWidthTabs();
...@@ -255,7 +256,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper { ...@@ -255,7 +256,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper {
this.backgroundColor, this.backgroundColor,
this.indicatorColor, this.indicatorColor,
this.textAndIcons, this.textAndIcons,
this.scrollable: false, this.isScrollable: false,
this.onLayoutChanged this.onLayoutChanged
}) : super(key: key, children: children); }) : super(key: key, children: children);
...@@ -263,7 +264,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper { ...@@ -263,7 +264,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper {
final Color backgroundColor; final Color backgroundColor;
final Color indicatorColor; final Color indicatorColor;
final bool textAndIcons; final bool textAndIcons;
final bool scrollable; final bool isScrollable;
final LayoutChanged onLayoutChanged; final LayoutChanged onLayoutChanged;
RenderTabBar get root => super.root; RenderTabBar get root => super.root;
...@@ -275,7 +276,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper { ...@@ -275,7 +276,7 @@ class TabBarWrapper extends MultiChildRenderObjectWrapper {
root.backgroundColor = backgroundColor; root.backgroundColor = backgroundColor;
root.indicatorColor = indicatorColor; root.indicatorColor = indicatorColor;
root.textAndIcons = textAndIcons; root.textAndIcons = textAndIcons;
root.scrollable = scrollable; root.isScrollable = isScrollable;
root.onLayoutChanged = onLayoutChanged; root.onLayoutChanged = onLayoutChanged;
} }
} }
...@@ -345,32 +346,54 @@ class Tab extends Component { ...@@ -345,32 +346,54 @@ class Tab extends Component {
} }
} }
class _TabsScrollBehavior extends BoundedBehavior {
_TabsScrollBehavior({ double contentsSize: 0.0, double containerSize: 0.0 })
: super(contentsSize: contentsSize, containerSize: containerSize);
bool isScrollable = true;
Simulation release(double position, double velocity) {
if (!isScrollable)
return null;
double velocityPerSecond = velocity * 1000.0;
return new BoundedFrictionSimulation(
_kTabBarScrollDrag, position, velocityPerSecond, minScrollOffset, maxScrollOffset
);
}
double applyCurve(double scrollOffset, double scrollDelta) {
return (isScrollable) ? super.applyCurve(scrollOffset, scrollDelta) : 0.0;
}
}
class TabBar extends Scrollable { class TabBar extends Scrollable {
TabBar({ TabBar({
Key key, Key key,
this.labels, this.labels,
this.selectedIndex: 0, this.selectedIndex: 0,
this.onChanged, this.onChanged,
this.scrollable: false this.isScrollable: false
}) : super(key: key, direction: ScrollDirection.horizontal); }) : super(key: key, direction: ScrollDirection.horizontal);
Iterable<TabLabel> labels; Iterable<TabLabel> labels;
int selectedIndex; int selectedIndex;
SelectedIndexChanged onChanged; SelectedIndexChanged onChanged;
bool scrollable; bool isScrollable;
void syncFields(TabBar source) { void syncFields(TabBar source) {
super.syncFields(source); super.syncFields(source);
labels = source.labels; labels = source.labels;
selectedIndex = source.selectedIndex; selectedIndex = source.selectedIndex;
onChanged = source.onChanged; onChanged = source.onChanged;
scrollable = source.scrollable; isScrollable = source.isScrollable;
if (!scrollable) if (!isScrollable)
scrollTo(0.0); scrollTo(0.0);
scrollBehavior.isScrollable = source.isScrollable;
} }
ScrollBehavior createScrollBehavior() => new FlingBehavior(); ScrollBehavior createScrollBehavior() => new _TabsScrollBehavior();
FlingBehavior get scrollBehavior => super.scrollBehavior; _TabsScrollBehavior get scrollBehavior => super.scrollBehavior;
void _handleTap(int tabIndex) { void _handleTap(int tabIndex) {
if (tabIndex != selectedIndex && onChanged != null) if (tabIndex != selectedIndex && onChanged != null)
...@@ -445,8 +468,8 @@ class TabBar extends Scrollable { ...@@ -445,8 +468,8 @@ class TabBar extends Scrollable {
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
indicatorColor: indicatorColor, indicatorColor: indicatorColor,
textAndIcons: textAndIcons, textAndIcons: textAndIcons,
scrollable: scrollable, isScrollable: isScrollable,
onLayoutChanged: scrollable ? _layoutChanged : null onLayoutChanged: isScrollable ? _layoutChanged : null
) )
) )
) )
...@@ -474,13 +497,13 @@ class TabNavigator extends Component { ...@@ -474,13 +497,13 @@ class TabNavigator extends Component {
this.views, this.views,
this.selectedIndex: 0, this.selectedIndex: 0,
this.onChanged, this.onChanged,
this.scrollable: false this.isScrollable: false
}) : super(key: key); }) : super(key: key);
final List<TabNavigatorView> views; final List<TabNavigatorView> views;
final int selectedIndex; final int selectedIndex;
final SelectedIndexChanged onChanged; final SelectedIndexChanged onChanged;
final bool scrollable; final bool isScrollable;
void _handleSelectedIndexChanged(int tabIndex) { void _handleSelectedIndexChanged(int tabIndex) {
if (onChanged != null) if (onChanged != null)
...@@ -495,7 +518,7 @@ class TabNavigator extends Component { ...@@ -495,7 +518,7 @@ class TabNavigator extends Component {
labels: views.map((view) => view.label), labels: views.map((view) => view.label),
onChanged: _handleSelectedIndexChanged, onChanged: _handleSelectedIndexChanged,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
scrollable: scrollable isScrollable: isScrollable
); );
Widget content = views[selectedIndex].buildContent(); Widget content = views[selectedIndex].buildContent();
......
...@@ -9,7 +9,7 @@ dependencies: ...@@ -9,7 +9,7 @@ dependencies:
mojo_services: ^0.0.15 mojo_services: ^0.0.15
mojo: ^0.0.17 mojo: ^0.0.17
mojom: ^0.0.17 mojom: ^0.0.17
newton: ^0.1.0 newton: ^0.1.2
sky_engine: ^0.0.1 sky_engine: ^0.0.1
sky_services: ^0.0.1 sky_services: ^0.0.1
sky_tools: ^0.0.4 sky_tools: ^0.0.4
......
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