From 3387bbaa37fe09cfdfd99b662507fd2b383e5c46 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 25 Sep 2015 14:03:11 -0700 Subject: [PATCH] Add ensureWidgetIsVisible to fn3 --- packages/flutter/lib/src/fn3/framework.dart | 8 +++ packages/flutter/lib/src/fn3/scrollable.dart | 58 +++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/fn3/framework.dart b/packages/flutter/lib/src/fn3/framework.dart index d5b172c767..d6e6c0a06f 100644 --- a/packages/flutter/lib/src/fn3/framework.dart +++ b/packages/flutter/lib/src/fn3/framework.dart @@ -396,6 +396,8 @@ typedef void ElementVisitor(Element element); abstract class BuildContext { InheritedWidget inheritedWidgetOfType(Type targetType); RenderObject findRenderObject(); + + void visitAncestorElements(bool visitor(Element element)); } /// Elements are the instantiations of Widget configurations. @@ -607,6 +609,12 @@ abstract class Element implements BuildContext { RenderObject findRenderObject() => renderObject; + void visitAncestorElements(bool visitor(Element element)) { + Element ancestor = _parent; + while (ancestor != null && visitor(ancestor)) + ancestor = ancestor._parent; + } + void dependenciesChanged() { assert(false); } diff --git a/packages/flutter/lib/src/fn3/scrollable.dart b/packages/flutter/lib/src/fn3/scrollable.dart index b5429c8c42..5c6cf21768 100644 --- a/packages/flutter/lib/src/fn3/scrollable.dart +++ b/packages/flutter/lib/src/fn3/scrollable.dart @@ -207,8 +207,62 @@ abstract class ScrollableState extends State { } } -// TODO(abarth): findScrollableAncestor -// TODO(abarth): ensureWidgetIsVisible +ScrollableState findScrollableAncestor(BuildContext context) { + ScrollableState result; + context.visitAncestorElements((Element element) { + if (element is StatefulComponentElement) { + if (element.state is ScrollableState) { + result = element.state; + return false; + } + } + return true; + }); + return result; +} + +Future ensureWidgetIsVisible(BuildContext context, { Duration duration, Curve curve }) { + assert(context.findRenderObject() is RenderBox); + // TODO(abarth): This function doesn't handle nested scrollable widgets. + + ScrollableState scrollable = findScrollableAncestor(context); + if (scrollable == null) + return new Future.value(); + + RenderBox targetBox = context.findRenderObject(); + assert(targetBox.attached); + Size targetSize = targetBox.size; + + RenderBox scrollableBox = scrollable.context.findRenderObject(); + assert(scrollableBox.attached); + Size scrollableSize = scrollableBox.size; + + double scrollOffsetDelta; + switch (scrollable.config.scrollDirection) { + case ScrollDirection.vertical: + Point targetCenter = targetBox.localToGlobal(new Point(0.0, targetSize.height / 2.0)); + Point scrollableCenter = scrollableBox.localToGlobal(new Point(0.0, scrollableSize.height / 2.0)); + scrollOffsetDelta = targetCenter.y - scrollableCenter.y; + break; + case ScrollDirection.horizontal: + Point targetCenter = targetBox.localToGlobal(new Point(targetSize.width / 2.0, 0.0)); + Point scrollableCenter = scrollableBox.localToGlobal(new Point(scrollableSize.width / 2.0, 0.0)); + scrollOffsetDelta = targetCenter.x - scrollableCenter.x; + break; + case ScrollDirection.both: + assert(false); // See https://github.com/flutter/engine/issues/888 + break; + } + + ExtentScrollBehavior scrollBehavior = scrollable.scrollBehavior; + double scrollOffset = (scrollable.scrollOffset + scrollOffsetDelta) + .clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset); + + if (scrollOffset != scrollable.scrollOffset) + return scrollable.scrollTo(scrollOffset, duration: duration, curve: curve); + + return new Future.value(); +} /// A simple scrollable widget that has a single child. Use this component if /// you are not worried about offscreen widgets consuming resources.