浏览代码

Implement GridView and ScrollableListView.

/main
Yuncong 6 年前
当前提交
3f57f07d
共有 3 个文件被更改,包括 710 次插入1 次删除
  1. 329
      Runtime/widgets/scroll_view.cs
  2. 379
      Runtime/material/reorderable_list.cs
  3. 3
      Runtime/material/reorderable_list.cs.meta

329
Runtime/widgets/scroll_view.cs


using System;
using com.unity.uiwidgets.Runtime.rendering;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;

base.debugFillProperties(properties);
properties.add(new FloatProperty("itemExtent", this.itemExtent,
defaultValue: Diagnostics.kNullDefaultValue));
}
}
public class GridView : BoxScrollView {
public GridView(
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,
SliverGridDelegate gridDelegate = null,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
D.assert(gridDelegate != null);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget>(),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public GridView(
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,
SliverGridDelegate gridDelegate = 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.gridDelegate = gridDelegate;
this.childrenDelegate = new SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView 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,
SliverGridDelegate gridDelegate = null,
IndexedWidgetBuilder itemBuilder = null,
int? itemCount = null,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
gridDelegate: gridDelegate,
itemBuilder: itemBuilder,
itemCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
cacheExtent: cacheExtent
);
}
public GridView(
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,
SliverGridDelegate gridDelegate = 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(gridDelegate != null);
D.assert(childrenDelegate != null);
this.gridDelegate = gridDelegate;
this.childrenDelegate = childrenDelegate;
}
public static GridView 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,
SliverGridDelegate gridDelegate = null,
SliverChildDelegate childrenDelegate = null,
float? cacheExtent = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
gridDelegate: gridDelegate,
childrenDelegate: childrenDelegate,
cacheExtent: cacheExtent
);
}
public GridView(
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
int? crossAxisCount = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
this.gridDelegate = new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget>(),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView count(
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
int? crossAxisCount = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
cacheExtent: cacheExtent,
children: children
);
}
public GridView(
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? maxCrossAxisExtent = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding
) {
this.gridDelegate = new SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget> { },
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView extent(
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? maxCrossAxisExtent = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
List<Widget> children = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
children: children
);
}
public readonly SliverGridDelegate gridDelegate;
public readonly SliverChildDelegate childrenDelegate;
protected override Widget buildChildLayout(BuildContext context) {
return new SliverGrid(
layoutDelegate: this.childrenDelegate,
gridDelegate: this.gridDelegate
);
}
}
}

379
Runtime/material/reorderable_list.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
namespace Unity.UIWidgets.material {
public delegate void ReorderCallback(int oldIndex, int newIndex);
public class ReorderableListView : StatefulWidget {
ReorderableListView(
Widget header = null,
List<Widget> children = null,
ReorderCallback onReorder = null,
Axis scrollDirection = Axis.vertical,
EdgeInsets padding = null
) {
D.assert(onReorder != null);
D.assert(children != null);
D.assert(
children.All((Widget w) => w.key != null),
"All children of this widget must have a key."
);
this.header = header;
this.children = children;
this.scrollDirection = scrollDirection;
this.padding = padding;
this.onReorder = onReorder;
}
public readonly Widget header;
public readonly List<Widget> children;
public readonly Axis scrollDirection;
public readonly EdgeInsets padding;
public readonly ReorderCallback onReorder;
public override State createState() {
return new _ReorderableListViewState();
}
}
class _ReorderableListViewState : State<ReorderableListView> {
GlobalKey _overlayKey = GlobalKey.key(debugLabel: "$ReorderableListView overlay key");
OverlayEntry _listOverlayEntry;
public override void initState() {
base.initState();
this._listOverlayEntry = new OverlayEntry(
opaque: true,
builder: (BuildContext context) => {
return new _ReorderableListContent(
header: this.widget.header,
children: this.widget.children,
scrollDirection: this.widget.scrollDirection,
onReorder: this.widget.onReorder,
padding: this.widget.padding
);
}
);
}
public override Widget build(BuildContext context) {
return new Overlay(
key: this._overlayKey,
initialEntries: new List<OverlayEntry> {
this._listOverlayEntry
});
}
}
class _ReorderableListContent : StatefulWidget {
public _ReorderableListContent(
Widget header,
List<Widget> children,
Axis scrollDirection,
EdgeInsets padding,
ReorderCallback onReorder
) {
this.header = header;
this.children = children;
this.scrollDirection = scrollDirection;
this.padding = padding;
this.onReorder = onReorder;
}
public readonly Widget header;
public readonly List<Widget> children;
public readonly Axis scrollDirection;
public readonly EdgeInsets padding;
public readonly ReorderCallback onReorder;
public override State createState() {
return new _ReorderableListContentState();
}
}
class _ReorderableListContentState : TickerProviderStateMixin<_ReorderableListContent> {
const float _defaultDropAreaExtent = 100.0f;
const float _dropAreaMargin = 8.0f;
readonly TimeSpan _reorderAnimationDuration = new TimeSpan(0, 0, 0, 0, 200);
readonly TimeSpan _scrollAnimationDuration = new TimeSpan(0, 0, 0, 0, 200);
ScrollController _scrollController;
AnimationController _entranceController;
AnimationController _ghostController;
Key _dragging;
Size _draggingFeedbackSize;
int _dragStartIndex = 0;
int _ghostIndex = 0;
int _currentIndex = 0;
int _nextIndex = 0;
bool _scrolling = false;
float _dropAreaExtent {
get {
if (this._draggingFeedbackSize == null) {
return _defaultDropAreaExtent;
}
float dropAreaWithoutMargin;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
dropAreaWithoutMargin = this._draggingFeedbackSize.width;
break;
case Axis.vertical:
default:
dropAreaWithoutMargin = this._draggingFeedbackSize.height;
break;
}
return dropAreaWithoutMargin + _dropAreaMargin;
}
}
public override void initState() {
base.initState();
this._entranceController = new AnimationController(vsync: this, duration: this._reorderAnimationDuration);
this._ghostController = new AnimationController(vsync: this, duration: this._reorderAnimationDuration);
this._entranceController.addStatusListener(this._onEntranceStatusChanged);
}
public override void didChangeDependencies() {
this._scrollController = PrimaryScrollController.of(this.context) ?? new ScrollController();
base.didChangeDependencies();
}
public override void dispose() {
this._entranceController.dispose();
this._ghostController.dispose();
base.dispose();
}
void _requestAnimationToNextIndex() {
if (this._entranceController.isCompleted) {
this._ghostIndex = this._currentIndex;
if (this._nextIndex == this._currentIndex) {
return;
}
this._currentIndex = this._nextIndex;
this._ghostController.reverse(from: 1.0f);
this._entranceController.forward(from: 0.0f);
}
}
void _onEntranceStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.completed) {
this.setState(() => { this._requestAnimationToNextIndex(); });
}
}
void _scrollTo(BuildContext context) {
if (this._scrolling) {
return;
}
RenderObject contextObject = context.findRenderObject();
RenderAbstractViewport viewport = RenderViewportUtils.of(contextObject);
D.assert(viewport != null);
float margin = this._dropAreaExtent;
float scrollOffset = this._scrollController.offset;
float topOffset = Mathf.Max(this._scrollController.position.minScrollExtent,
viewport.getOffsetToReveal(contextObject, 0.0f).offset - margin
);
float bottomOffset = Mathf.Min(this._scrollController.position.maxScrollExtent,
viewport.getOffsetToReveal(contextObject, 1.0f).offset + margin
);
bool onScreen = scrollOffset <= topOffset && scrollOffset >= bottomOffset;
if (!onScreen) {
this._scrolling = true;
this._scrollController.position.animateTo(
scrollOffset < bottomOffset ? bottomOffset : topOffset,
duration: this._scrollAnimationDuration,
curve: Curves.easeInOut
).Then(() => { this.setState(() => { this._scrolling = false; }); });
}
}
Widget _buildContainerForScrollDirection(List<Widget> children = null) {
switch (this.widget.scrollDirection) {
case Axis.horizontal:
return new Row(children: children);
case Axis.vertical:
default:
return new Column(children: children);
}
}
Widget _wrap(Widget toWrap, int index, BoxConstraints constraints) {
D.assert(toWrap.key != null);
GlobalObjectKey<State> keyIndexGlobalKey = new GlobalObjectKey<State>(toWrap.key);
void onDragStarted() {
this.setState(() => {
this._dragging = toWrap.key;
this._dragStartIndex = index;
this._ghostIndex = index;
this._currentIndex = index;
this._entranceController.setValue(1.0f);
this._draggingFeedbackSize = keyIndexGlobalKey.currentContext.size;
});
}
void reorder(int startIndex, int endIndex) {
this.setState(() => {
if (startIndex != endIndex) {
this.widget.onReorder(startIndex, endIndex);
}
this._ghostController.reverse(from: 0.1f);
this._entranceController.reverse(from: 0.1f);
this._dragging = null;
});
}
void onDragEnded() {
reorder(this._dragStartIndex, this._currentIndex);
}
Widget buildDragTarget(BuildContext context, List<Key> acceptedCandidates, List<Key> rejectedCandidates) {
Widget child = new LongPressDraggable<Key>(
maxSimultaneousDrags: 1,
axis: this.widget.scrollDirection,
data: toWrap.key,
child: new SizedBox(),
childWhenDragging: new SizedBox(),
dragAnchor: DragAnchor.child,
onDragStarted: onDragStarted,
onDragCompleted: onDragEnded,
onDraggableCanceled: (Velocity velocity, Offset offset) => { onDragEnded(); }
);
if (index >= this.widget.children.Count) {
child = toWrap;
}
Widget spacing;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
spacing = new SizedBox(width: this._dropAreaExtent);
break;
case Axis.vertical:
default:
spacing = new SizedBox(height: this._dropAreaExtent);
break;
}
if (this._currentIndex == index) {
return this._buildContainerForScrollDirection(children: new List<Widget> {
new SizeTransition(
sizeFactor: this._entranceController,
axis: this.widget.scrollDirection,
child: spacing
),
child
});
}
if (this._ghostIndex == index) {
return this._buildContainerForScrollDirection(children: new List<Widget> {
new SizeTransition(
sizeFactor: this._ghostController,
axis: this.widget.scrollDirection,
child: spacing
),
child
});
}
return child;
}
return new Builder(builder: (BuildContext context) => {
return new DragTarget<Key>(
builder: buildDragTarget,
onWillAccept: (Key toAccept) => {
this.setState(() => {
this._nextIndex = index;
this._requestAnimationToNextIndex();
});
this._scrollTo(this.context);
return this._dragging == toAccept && toAccept != toWrap.key;
},
onAccept: (Key accepted) => { },
onLeave: (Key leaving) => { }
);
});
}
public override Widget build(BuildContext context) {
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
return new LayoutBuilder(builder: (BuildContext _, BoxConstraints constraints) => {
List<Widget> wrappedChildren = new List<Widget> { };
if (this.widget.header != null) {
wrappedChildren.Add(this.widget.header);
}
for (int i = 0; i < this.widget.children.Count; i += 1) {
wrappedChildren.Add(this._wrap(this.widget.children[i], i, constraints));
}
Key endWidgetKey = Key.key("DraggableList - End Widget");
Widget finalDropArea;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
finalDropArea = new SizedBox(
key: endWidgetKey,
width: _defaultDropAreaExtent,
height: constraints.maxHeight
);
break;
case Axis.vertical:
default:
finalDropArea = new SizedBox(
key: endWidgetKey,
height: _defaultDropAreaExtent,
width: constraints.maxWidth
);
break;
}
wrappedChildren.Add(this._wrap(
finalDropArea, this.widget.children.Count,
constraints)
);
return new SingleChildScrollView(
scrollDirection: this.widget.scrollDirection,
child: this._buildContainerForScrollDirection(children: wrappedChildren),
padding: this.widget.padding,
controller: this._scrollController
);
});
}
}
}

3
Runtime/material/reorderable_list.cs.meta


fileFormatVersion: 2
guid: 730da7185538491389639e2cc7099a21
timeCreated: 1554301017
正在加载...
取消
保存