fzhangtj
6 年前
当前提交
1bc56ed7
共有 7 个文件被更改,包括 535 次插入 和 24 次删除
-
1Runtime/widgets/app.cs
-
55Runtime/widgets/basic.cs
-
85Samples/UIWidgetSample/NavigationCanvas.cs
-
238Runtime/rendering/custom_layout.cs
-
11Runtime/rendering/custom_layout.cs.meta
-
158Runtime/widgets/navigation_toolbar.cs
-
11Runtime/widgets/navigation_toolbar.cs.meta
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.rendering { |
|||
public class MultiChildLayoutParentData : ContainerParentDataMixinBoxParentData<RenderBox> { |
|||
public object id; |
|||
|
|||
public override string ToString() { |
|||
return $"{base.ToString()}; id={this.id}"; |
|||
} |
|||
} |
|||
|
|||
public abstract class MultiChildLayoutDelegate { |
|||
Dictionary<object, RenderBox> _idToChild; |
|||
HashSet<RenderBox> _debugChildrenNeedingLayout; |
|||
|
|||
public bool hasChild(object childId) { |
|||
return this._idToChild.getOrDefault(childId) != null; |
|||
} |
|||
|
|||
public Size layoutChild(object childId, BoxConstraints constraints) { |
|||
RenderBox child = this._idToChild[childId]; |
|||
D.assert(() => { |
|||
if (child == null) |
|||
throw new UIWidgetsError( |
|||
$"The {this} custom multichild layout delegate tried to lay out a non-existent child.\n" + |
|||
$"There is no child with the id \"{childId}\"." |
|||
); |
|||
|
|||
if (!this._debugChildrenNeedingLayout.Remove(child)) |
|||
throw new UIWidgetsError( |
|||
$"The $this custom multichild layout delegate tried to lay out the child with id \"{childId}\" more than once.\n" + |
|||
"Each child must be laid out exactly once." |
|||
); |
|||
|
|||
try { |
|||
D.assert(constraints.debugAssertIsValid(isAppliedConstraint: true)); |
|||
} |
|||
catch (AssertionError exception) { |
|||
throw new UIWidgetsError( |
|||
$"The {this} custom multichild layout delegate provided invalid box constraints for the child with id \"{childId}\".\n" + |
|||
$"{exception}n" + |
|||
"The minimum width and height must be greater than or equal to zero.\n" + |
|||
"The maximum width must be greater than or equal to the minimum width.\n" + |
|||
"The maximum height must be greater than or equal to the minimum height."); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
child.layout(constraints, parentUsesSize: true); |
|||
return child.size; |
|||
} |
|||
|
|||
public void positionChild(object childId, Offset offset) { |
|||
RenderBox child = this._idToChild[childId]; |
|||
D.assert(() => { |
|||
if (child == null) |
|||
throw new UIWidgetsError( |
|||
$"The {this} custom multichild layout delegate tried to position out a non-existent child:\n" + |
|||
$"There is no child with the id \"{childId}\"." |
|||
); |
|||
|
|||
if (offset == null) |
|||
throw new UIWidgetsError( |
|||
$"The {this} custom multichild layout delegate provided a null position for the child with id \"{childId}\"." |
|||
); |
|||
|
|||
return true; |
|||
}); |
|||
MultiChildLayoutParentData childParentData = (MultiChildLayoutParentData) child.parentData; |
|||
childParentData.offset = offset; |
|||
} |
|||
|
|||
string _debugDescribeChild(RenderBox child) { |
|||
MultiChildLayoutParentData childParentData = (MultiChildLayoutParentData) child.parentData; |
|||
return $"{childParentData.id}: {child}"; |
|||
} |
|||
|
|||
|
|||
internal void _callPerformLayout(Size size, RenderBox firstChild) { |
|||
Dictionary<object, RenderBox> previousIdToChild = this._idToChild; |
|||
|
|||
HashSet<RenderBox> debugPreviousChildrenNeedingLayout = null; |
|||
D.assert(() => { |
|||
debugPreviousChildrenNeedingLayout = this._debugChildrenNeedingLayout; |
|||
this._debugChildrenNeedingLayout = new HashSet<RenderBox>(); |
|||
return true; |
|||
}); |
|||
|
|||
try { |
|||
this._idToChild = new Dictionary<object, RenderBox>(); |
|||
RenderBox child = firstChild; |
|||
while (child != null) { |
|||
MultiChildLayoutParentData childParentData = (MultiChildLayoutParentData) child.parentData; |
|||
D.assert(() => { |
|||
if (childParentData.id == null) |
|||
throw new UIWidgetsError( |
|||
"The following child has no ID:\n" + |
|||
$" {child}\n" + |
|||
"Every child of a RenderCustomMultiChildLayoutBox must have an ID in its parent data." |
|||
); |
|||
|
|||
return true; |
|||
}); |
|||
this._idToChild[childParentData.id] = child; |
|||
D.assert(() => { |
|||
this._debugChildrenNeedingLayout.Add(child); |
|||
return true; |
|||
}); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
this.performLayout(size); |
|||
D.assert(() => { |
|||
if (this._debugChildrenNeedingLayout.isNotEmpty()) { |
|||
if (this._debugChildrenNeedingLayout.Count > 1) |
|||
throw new UIWidgetsError( |
|||
$"The $this custom multichild layout delegate forgot to lay out the following children:\n" + |
|||
$" {string.Join("\n ", this._debugChildrenNeedingLayout.Select(this._debugDescribeChild))}\n" + |
|||
"Each child must be laid out exactly once." |
|||
); |
|||
else |
|||
throw new UIWidgetsError( |
|||
$"The $this custom multichild layout delegate forgot to lay out the following child:\n" + |
|||
$" {this._debugDescribeChild(this._debugChildrenNeedingLayout.First())}\n" + |
|||
"Each child must be laid out exactly once." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
} |
|||
finally { |
|||
this._idToChild = previousIdToChild; |
|||
D.assert(() => { |
|||
this._debugChildrenNeedingLayout = debugPreviousChildrenNeedingLayout; |
|||
return true; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public virtual Size getSize(BoxConstraints constraints) { |
|||
return constraints.biggest; |
|||
} |
|||
|
|||
|
|||
public abstract void performLayout(Size size); |
|||
|
|||
|
|||
public abstract bool shouldRelayout(MultiChildLayoutDelegate oldDelegate); |
|||
|
|||
public override string ToString() { |
|||
return $"{this.GetType()}"; |
|||
} |
|||
} |
|||
|
|||
public class RenderCustomMultiChildLayoutBox : RenderBoxContainerDefaultsMixinContainerRenderObjectMixinRenderBox< |
|||
RenderBox |
|||
, MultiChildLayoutParentData> { |
|||
public RenderCustomMultiChildLayoutBox( |
|||
List<RenderBox> children = null, |
|||
MultiChildLayoutDelegate layoutDelegate = null |
|||
) { |
|||
D.assert(layoutDelegate != null); |
|||
this._delegate = layoutDelegate; |
|||
this.addAll(children); |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is MultiChildLayoutParentData)) |
|||
child.parentData = new MultiChildLayoutParentData(); |
|||
} |
|||
|
|||
public MultiChildLayoutDelegate layoutDelegate { |
|||
get => this._delegate; |
|||
set { |
|||
D.assert(value != null); |
|||
if (this._delegate == value) |
|||
return; |
|||
if (value.GetType() != this._delegate.GetType() || value.shouldRelayout(this._delegate)) |
|||
this.markNeedsLayout(); |
|||
this._delegate = value; |
|||
} |
|||
} |
|||
|
|||
MultiChildLayoutDelegate _delegate; |
|||
|
|||
|
|||
Size _getSize(BoxConstraints constraints) { |
|||
D.assert(constraints.debugAssertIsValid()); |
|||
return constraints.constrain(this._delegate.getSize(constraints)); |
|||
} |
|||
|
|||
protected override double computeMinIntrinsicWidth(double height) { |
|||
double width = this._getSize(BoxConstraints.tightForFinite(height: height)).width; |
|||
if (width.isFinite()) |
|||
return width; |
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicWidth(double height) { |
|||
double width = this._getSize(BoxConstraints.tightForFinite(height: height)).width; |
|||
if (width.isFinite()) |
|||
return width; |
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMinIntrinsicHeight(double width) { |
|||
double height = this._getSize(BoxConstraints.tightForFinite(width: width)).height; |
|||
if (height.isFinite()) |
|||
return height; |
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicHeight(double width) { |
|||
double height = this._getSize(BoxConstraints.tightForFinite(width: width)).height; |
|||
if (height.isFinite()) |
|||
return height; |
|||
return 0.0; |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
this.size = this._getSize(this.constraints); |
|||
this.layoutDelegate._callPerformLayout(this.size, this.firstChild); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
this.defaultPaint(context, offset); |
|||
} |
|||
|
|||
protected override bool hitTestChildren(HitTestResult result, Offset position) { |
|||
return this.defaultHitTestChildren(result, position: position); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b5b9bc11eb396425ab97e383d769356c |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class NavigationToolbar : StatelessWidget { |
|||
public NavigationToolbar(Key key = null, Widget leading = null, Widget middle = null, |
|||
Widget trailing = null, bool centerMiddle = true, double middleSpacing = kMiddleSpacing) : base(key) { |
|||
this.leading = leading; |
|||
this.middle = middle; |
|||
this.trailing = trailing; |
|||
this.centerMiddle = centerMiddle; |
|||
this.middleSpacing = middleSpacing; |
|||
} |
|||
|
|||
public const double kMiddleSpacing = 16.0; |
|||
|
|||
public readonly Widget leading; |
|||
public readonly Widget middle; |
|||
public readonly Widget trailing; |
|||
public readonly bool centerMiddle; |
|||
public readonly double middleSpacing; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(WidgetsD.debugCheckHasDirectionality(context)); |
|||
List<Widget> children = new List<Widget>(); |
|||
|
|||
if (this.leading != null) |
|||
children.Add(new LayoutId(id: _ToolbarSlot.leading, child: this.leading)); |
|||
|
|||
if (this.middle != null) |
|||
children.Add(new LayoutId(id: _ToolbarSlot.middle, child: this.middle)); |
|||
|
|||
if (this.trailing != null) |
|||
children.Add(new LayoutId(id: _ToolbarSlot.trailing, child: this.trailing)); |
|||
|
|||
TextDirection textDirection = Directionality.of(context); |
|||
return new CustomMultiChildLayout( |
|||
layoutDelegate: new _ToolbarLayout( |
|||
centerMiddle: this.centerMiddle, |
|||
middleSpacing: this.middleSpacing, |
|||
textDirection: textDirection |
|||
), |
|||
children: children |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal enum _ToolbarSlot { |
|||
leading, |
|||
middle, |
|||
trailing, |
|||
} |
|||
|
|||
internal class _ToolbarLayout : MultiChildLayoutDelegate { |
|||
public _ToolbarLayout( |
|||
bool? centerMiddle = true, |
|||
double? middleSpacing = null, |
|||
TextDirection? textDirection = null |
|||
) { |
|||
D.assert(textDirection != null); |
|||
D.assert(middleSpacing != null); |
|||
this.centerMiddle = centerMiddle??true; |
|||
this.middleSpacing = middleSpacing ?? 0.0; |
|||
this.textDirection = textDirection ?? TextDirection.ltr; |
|||
} |
|||
|
|||
|
|||
public readonly bool centerMiddle; |
|||
|
|||
public readonly double middleSpacing; |
|||
|
|||
public readonly TextDirection textDirection; |
|||
|
|||
public override void performLayout(Size size) { |
|||
double leadingWidth = 0.0; |
|||
double trailingWidth = 0.0; |
|||
|
|||
if (this.hasChild(_ToolbarSlot.leading)) { |
|||
BoxConstraints constraints = new BoxConstraints( |
|||
minWidth: 0.0, |
|||
maxWidth: size.width / 3.0, |
|||
minHeight: size.height, |
|||
maxHeight: size.height |
|||
); |
|||
leadingWidth = this.layoutChild(_ToolbarSlot.leading, constraints).width; |
|||
double leadingX = 0.0; |
|||
switch (this.textDirection) { |
|||
case TextDirection.rtl: |
|||
leadingX = size.width - leadingWidth; |
|||
break; |
|||
case TextDirection.ltr: |
|||
leadingX = 0.0; |
|||
break; |
|||
} |
|||
|
|||
this.positionChild(_ToolbarSlot.leading, new Offset(leadingX, 0.0)); |
|||
} |
|||
|
|||
if (this.hasChild(_ToolbarSlot.trailing)) { |
|||
BoxConstraints constraints = BoxConstraints.loose(size); |
|||
Size trailingSize = this.layoutChild(_ToolbarSlot.trailing, constraints); |
|||
double trailingX = 0.0; |
|||
switch (this.textDirection) { |
|||
case TextDirection.rtl: |
|||
trailingX = 0.0; |
|||
break; |
|||
case TextDirection.ltr: |
|||
trailingX = size.width - trailingSize.width; |
|||
break; |
|||
} |
|||
|
|||
double trailingY = (size.height - trailingSize.height) / 2.0; |
|||
trailingWidth = trailingSize.width; |
|||
this.positionChild(_ToolbarSlot.trailing, new Offset(trailingX, trailingY)); |
|||
} |
|||
|
|||
if (this.hasChild(_ToolbarSlot.middle)) { |
|||
double maxWidth = Math.Max(size.width - leadingWidth - trailingWidth - this.middleSpacing * 2.0, 0.0); |
|||
BoxConstraints constraints = BoxConstraints.loose(size).copyWith(maxWidth: maxWidth); |
|||
Size middleSize = this.layoutChild(_ToolbarSlot.middle, constraints); |
|||
|
|||
double middleStartMargin = leadingWidth + this.middleSpacing; |
|||
double middleStart = middleStartMargin; |
|||
double middleY = (size.height - middleSize.height) / 2.0; |
|||
// If the centered middle will not fit between the leading and trailing
|
|||
// widgets, then align its left or right edge with the adjacent boundary.
|
|||
if (this.centerMiddle) { |
|||
middleStart = (size.width - middleSize.width) / 2.0; |
|||
if (middleStart + middleSize.width > size.width - trailingWidth) |
|||
middleStart = size.width - trailingWidth - middleSize.width; |
|||
else if (middleStart < middleStartMargin) |
|||
middleStart = middleStartMargin; |
|||
} |
|||
|
|||
double middleX = 0.0; |
|||
switch (this.textDirection) { |
|||
case TextDirection.rtl: |
|||
middleX = size.width - middleSize.width - middleStart; |
|||
break; |
|||
case TextDirection.ltr: |
|||
middleX = middleStart; |
|||
break; |
|||
} |
|||
|
|||
this.positionChild(_ToolbarSlot.middle, new Offset(middleX, middleY)); |
|||
} |
|||
} |
|||
|
|||
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) { |
|||
return ((_ToolbarLayout) oldDelegate).centerMiddle != this.centerMiddle |
|||
|| ((_ToolbarLayout) oldDelegate).middleSpacing != this.middleSpacing |
|||
|| ((_ToolbarLayout) oldDelegate).textDirection != this.textDirection; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0d3291a5dbe68445896df6360fda57c8 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue