using System; using System.Collections.Generic; using Unity.UIWidgets.foundation; using Unity.UIWidgets.painting; using Unity.UIWidgets.rendering; using UnityEngine; namespace Unity.UIWidgets.widgets { public abstract class ScrollView : StatelessWidget { protected ScrollView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, float? cacheExtent = null ) : base(key: key) { D.assert(!(controller != null && primary == true), "Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. " + "You cannot both set primary to true and pass an explicit controller."); primary = primary ?? controller == null && scrollDirection == Axis.vertical; physics = physics ?? (primary.Value ? new AlwaysScrollableScrollPhysics() : null); this.scrollDirection = scrollDirection; this.reverse = reverse; this.controller = controller; this.primary = primary.Value; this.physics = physics; this.shrinkWrap = shrinkWrap; this.cacheExtent = cacheExtent; } public readonly Axis scrollDirection; public readonly bool reverse; public readonly ScrollController controller; public readonly bool primary; public readonly ScrollPhysics physics; public readonly bool shrinkWrap; public readonly float? cacheExtent; protected AxisDirection getDirection(BuildContext context) { return LayoutUtils.getAxisDirectionFromAxisReverseAndDirectionality( context, this.scrollDirection, this.reverse); } protected abstract List buildSlivers(BuildContext context); protected Widget buildViewport( BuildContext context, ViewportOffset offset, AxisDirection axisDirection, List slivers ) { if (this.shrinkWrap) { return new ShrinkWrappingViewport( axisDirection: axisDirection, offset: offset, slivers: slivers ); } return new Viewport( axisDirection: axisDirection, offset: offset, slivers: slivers, cacheExtent: this.cacheExtent ); } public override Widget build(BuildContext context) { List slivers = this.buildSlivers(context); AxisDirection axisDirection = this.getDirection(context); ScrollController scrollController = this.primary ? PrimaryScrollController.of(context) : this.controller; Scrollable scrollable = new Scrollable( axisDirection: axisDirection, controller: scrollController, physics: this.physics, viewportBuilder: (viewportContext, offset) => this.buildViewport(viewportContext, offset, axisDirection, slivers) ); return this.primary && scrollController != null ? (Widget) PrimaryScrollController.none(child: scrollable) : scrollable; } public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.add(new EnumProperty("scrollDirection", this.scrollDirection)); properties.add(new FlagProperty("reverse", value: this.reverse, ifTrue: "reversed", showName: true)); properties.add(new DiagnosticsProperty("controller", this.controller, showName: false, defaultValue: Diagnostics.kNullDefaultValue)); properties.add(new FlagProperty("primary", value: this.primary, ifTrue: "using primary controller", showName: true)); properties.add(new DiagnosticsProperty("physics", this.physics, showName: false, defaultValue: Diagnostics.kNullDefaultValue)); properties.add(new FlagProperty("shrinkWrap", value: this.shrinkWrap, ifTrue: "shrink-wrapping", showName: true)); } } public class CustomScrollView : ScrollView { public CustomScrollView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, float? cacheExtent = null, List slivers = null ) : base( key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, cacheExtent: cacheExtent ) { this.slivers = slivers ?? new List(); } public readonly List slivers; protected override List buildSlivers(BuildContext context) { return this.slivers; } } public abstract class BoxScrollView : ScrollView { public BoxScrollView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? cacheExtent = null ) : base( key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, cacheExtent: cacheExtent ) { this.padding = padding; } public readonly EdgeInsets padding; protected override List buildSlivers(BuildContext context) { Widget sliver = this.buildChildLayout(context); EdgeInsets effectivePadding = this.padding; // no need to check MediaQuery for now. if (effectivePadding != null) { sliver = new SliverPadding(padding: effectivePadding, sliver: sliver); } return new List {sliver}; } protected abstract Widget buildChildLayout(BuildContext context); public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.add(new DiagnosticsProperty("padding", this.padding, defaultValue: Diagnostics.kNullDefaultValue)); } } public class ListView : BoxScrollView { public ListView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? itemExtent = null, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, float? cacheExtent = null, List children = null ) : base( key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, padding: padding, cacheExtent: cacheExtent ) { this.itemExtent = itemExtent; this.childrenDelegate = new SliverChildListDelegate( children, addAutomaticKeepAlives: addAutomaticKeepAlives, addRepaintBoundaries: addRepaintBoundaries ); } ListView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? itemExtent = null, IndexedWidgetBuilder itemBuilder = null, int? itemCount = null, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, float? cacheExtent = null ) : base(key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, padding: padding, cacheExtent: cacheExtent ) { this.itemExtent = itemExtent; this.childrenDelegate = new SliverChildBuilderDelegate( itemBuilder, childCount: itemCount, addAutomaticKeepAlives: addAutomaticKeepAlives, addRepaintBoundaries: addRepaintBoundaries ); } public static ListView builder( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? itemExtent = null, IndexedWidgetBuilder itemBuilder = null, int? itemCount = null, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, float? cacheExtent = null ) { return new ListView( key, scrollDirection, reverse, controller, primary, physics, shrinkWrap, padding, itemExtent, itemBuilder, itemCount, addAutomaticKeepAlives, addRepaintBoundaries ); } ListView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, IndexedWidgetBuilder itemBuilder = null, IndexedWidgetBuilder separatorBuilder = null, int itemCount = 0, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, float? cacheExtent = null ) : base( key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, padding: padding, cacheExtent: cacheExtent ) { D.assert(itemBuilder != null); D.assert(separatorBuilder != null); D.assert(itemCount >= 0); this.itemExtent = null; this.childrenDelegate = new SliverChildBuilderDelegate( (context, index) => { int itemIndex = index / 2; return index % 2 == 0 ? itemBuilder(context, itemIndex) : separatorBuilder(context, itemIndex); }, childCount: Mathf.Max(0, itemCount * 2 - 1), addAutomaticKeepAlives: addAutomaticKeepAlives, addRepaintBoundaries: addRepaintBoundaries ); } public static ListView seperated( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, IndexedWidgetBuilder itemBuilder = null, IndexedWidgetBuilder separatorBuilder = null, int itemCount = 0, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, float? cacheExtent = null ) { return new ListView( key, scrollDirection, reverse, controller, primary, physics, shrinkWrap, padding, itemBuilder, separatorBuilder, itemCount, addAutomaticKeepAlives, addRepaintBoundaries, cacheExtent ); } ListView( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? itemExtent = null, SliverChildDelegate childrenDelegate = null, float? cacheExtent = null ) : base( key: key, scrollDirection: scrollDirection, reverse: reverse, controller: controller, primary: primary, physics: physics, shrinkWrap: shrinkWrap, padding: padding, cacheExtent: cacheExtent ) { D.assert(childrenDelegate != null); this.itemExtent = itemExtent; this.childrenDelegate = childrenDelegate; } public static ListView custom( Key key = null, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController controller = null, bool? primary = null, ScrollPhysics physics = null, bool shrinkWrap = false, EdgeInsets padding = null, float? itemExtent = null, SliverChildDelegate childrenDelegate = null, float? cacheExtent = null ) { return new ListView( key, scrollDirection, reverse, controller, primary, physics, shrinkWrap, padding, itemExtent, childrenDelegate, cacheExtent); } public readonly float? itemExtent; public readonly SliverChildDelegate childrenDelegate; protected override Widget buildChildLayout(BuildContext context) { if (this.itemExtent != null) { return new SliverFixedExtentList( del: this.childrenDelegate, itemExtent: this.itemExtent.Value ); } return new SliverList(del: this.childrenDelegate); } public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { base.debugFillProperties(properties); properties.add(new FloatProperty("itemExtent", this.itemExtent, defaultValue: Diagnostics.kNullDefaultValue)); } } }