浏览代码

Merge branch 'master' into 'master'

navigation bar & custom paint

See merge request upm-packages/ui-widgets/com.unity.uiwidgets!20
/main
Shenhua Gu 6 年前
当前提交
abd4640f
共有 12 个文件被更改,包括 942 次插入24 次删除
  1. 1
      Runtime/widgets/app.cs
  2. 104
      Runtime/widgets/basic.cs
  3. 73
      Samples/UIWidgetSample/Navigation.unity
  4. 85
      Samples/UIWidgetSample/NavigationCanvas.cs
  5. 238
      Runtime/rendering/custom_layout.cs
  6. 11
      Runtime/rendering/custom_layout.cs.meta
  7. 194
      Runtime/widgets/custom_paint.cs
  8. 11
      Runtime/widgets/custom_paint.cs.meta
  9. 158
      Runtime/widgets/navigation_toolbar.cs
  10. 11
      Runtime/widgets/navigation_toolbar.cs.meta
  11. 69
      Samples/UIWidgetSample/CustomPaintCanvas.cs
  12. 11
      Samples/UIWidgetSample/CustomPaintCanvas.cs.meta

1
Runtime/widgets/app.cs


return true;
});
result = new Directionality(child: result, TextDirection.ltr);
result = new WindowProvider(
window: this.widget.window,
child: result

104
Runtime/widgets/basic.cs


this.textDirection = textDirection;
}
public TextDirection textDirection;
public readonly TextDirection textDirection;
public static TextDirection of(BuildContext context) {
Directionality widget = context.inheritFromWidgetOfExactType(typeof(Directionality)) as Directionality;

this.opacity = opacity;
}
public double opacity;
public readonly double opacity;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderOpacity(opacity: this.opacity);

((RenderOpacity) renderObject).opacity = this.opacity;
}
}
public class CustomPaint : SingleChildRenderObjectWidget {
public CustomPaint(
Key key = null,
CustomPainter painter = null,
CustomPainter foregroundPainter = null,
Size size = null,
bool isComplex = false,
bool willChange = false,
Widget child = null
) : base(key: key, child: child) {
size = size ?? Size.zero;
this.size = size;
this.painter = painter;
this.foregroundPainter = foregroundPainter;
this.isComplex = isComplex;
this.willChange = willChange;
}
public readonly CustomPainter painter;
public readonly CustomPainter foregroundPainter;
public readonly Size size;
public readonly bool isComplex;
public readonly bool willChange;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderCustomPaint(
painter: this.painter,
foregroundPainter: this.foregroundPainter,
preferredSize: this.size,
isComplex: this.isComplex,
willChange: this.willChange
);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
((RenderCustomPaint) renderObject).painter = this.painter;
((RenderCustomPaint) renderObject).foregroundPainter = this.foregroundPainter;
((RenderCustomPaint) renderObject).preferredSize = this.size;
((RenderCustomPaint) renderObject).isComplex = this.isComplex;
((RenderCustomPaint)renderObject).willChange = this.willChange;
}
public override void didUnmountRenderObject(RenderObject renderObject) {
((RenderCustomPaint)renderObject).painter = null;
((RenderCustomPaint)renderObject).foregroundPainter = null;
}
}

widthFactor: widthFactor,
heightFactor: heightFactor,
child: child) {
}
}
public class LayoutId : ParentDataWidget<CustomMultiChildLayout> {
public LayoutId(
Key key = null,
object id = null,
Widget child = null
) : base(key: key ?? new ValueKey<object>(id), child: child) {
D.assert(child != null);
D.assert(id != null);
this.id = id;
}
public readonly object id;
public override void applyParentData(RenderObject renderObject) {
D.assert(renderObject.parentData is MultiChildLayoutParentData);
MultiChildLayoutParentData parentData = (MultiChildLayoutParentData) renderObject.parentData;
if (parentData.id != this.id) {
parentData.id = this.id;
var targetParent = renderObject.parent;
if (targetParent is RenderObject)
((RenderObject) targetParent).markNeedsLayout();
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<object>("id", this.id));
}
}
public class CustomMultiChildLayout : MultiChildRenderObjectWidget {
public CustomMultiChildLayout(
Key key = null,
MultiChildLayoutDelegate layoutDelegate = null,
List<Widget> children = null
) : base(key: key, children: children ?? new List<Widget>()) {
D.assert(layoutDelegate != null);
this.layoutDelegate = layoutDelegate;
}
public readonly MultiChildLayoutDelegate layoutDelegate;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderCustomMultiChildLayoutBox(layoutDelegate: this.layoutDelegate);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
((RenderCustomMultiChildLayoutBox) renderObject).layoutDelegate = this.layoutDelegate;
}
}

73
Samples/UIWidgetSample/Navigation.unity


m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
- {fileID: 927824195}
- {fileID: 1158582124}
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927824194}
m_CullTransparentMesh: 0
--- !u!1 &1158582123
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1158582124}
- component: {fileID: 1158582126}
- component: {fileID: 1158582125}
m_Layer: 5
m_Name: CustomPaint
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &1158582124
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1158582123}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 4286176}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1158582125
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1158582123}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5debfd6de8ea942d487383a56aad8491, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Texture: {fileID: 0}
m_UVRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
--- !u!222 &1158582126
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1158582123}
m_CullTransparentMesh: 0
--- !u!1 &1838283857
GameObject:

85
Samples/UIWidgetSample/NavigationCanvas.cs


using Unity.UIWidgets.animation;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using Color = Unity.UIWidgets.ui.Color;

)
);
}
return new Container(
color: new Color(0xFF888888),
child: new Center(child: new CustomButton(onPressed: () => {
Navigator.pushName(context, "/detail");
}, child: new Text("Go to Detail"))
));
return new NavigationPage(
body:new Container(
color: new Color(0xFF888888),
child: new Center(child: new CustomButton(onPressed: () => {
Navigator.pushName(context, "/detail");
}, child: new Text("Go to Detail"))
)),
title: "Home"
);
return new Container(
color: new Color(0xFF1389FD),
child: new Center(
child: new Column(
children: new List<Widget>() {
new CustomButton(onPressed: () => {
Navigator.pop(context);
}, child: new Text("Back")),
new CustomButton(onPressed: () => {
_Dialog.showDialog(context, builder: (BuildContext c) => new Dialog());
}, child: new Text("Show Dialog"))
}
)
));
return new NavigationPage(
body: new Container(
color: new Color(0xFF1389FD),
child: new Center(
child: new Column(
children: new List<Widget>() {
new CustomButton(onPressed: () => { Navigator.pop(context); }, child: new Text("Back")),
new CustomButton(
onPressed: () => {
_Dialog.showDialog(context, builder: (BuildContext c) => new Dialog());
}, child: new Text("Show Dialog"))
}
)
)),
title: "Detail");
}
}

child: this.child
)
);
}
}
class NavigationPage: StatelessWidget {
public readonly Widget body;
public readonly string title;
public NavigationPage(Widget body = null, string title = null) {
this.title = title;
this.body = body;
}
public override Widget build(BuildContext context) {
Widget back = null;
if (Navigator.of(context).canPop()) {
back = new CustomButton(onPressed: () => { Navigator.pop(context); },
child: new Text("Go Back"));
back = new Column(mainAxisAlignment: MainAxisAlignment.center, children: new List<Widget>(){back});
}
return new Container(
child: new Column(
children: new List<Widget>() {
new ConstrainedBox(constraints: new BoxConstraints(maxHeight:80),
child:new DecoratedBox(
decoration: new BoxDecoration(color: new Color(0XFFE1ECF4)),
child:new NavigationToolbar(leading: back,
middle: new Text(this.title, textAlign: TextAlign.center))))
,
new Flexible(child:this.body)
}
)
);
}
}

238
Runtime/rendering/custom_layout.cs


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);
}
}
}

11
Runtime/rendering/custom_layout.cs.meta


fileFormatVersion: 2
guid: b5b9bc11eb396425ab97e383d769356c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

194
Runtime/widgets/custom_paint.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.widgets {
public abstract class CustomPainter : Listenable {
public CustomPainter(Listenable repaint) {
this._repaint = repaint;
}
readonly Listenable _repaint;
public void addListener(VoidCallback listener) {
this._repaint?.addListener(listener);
}
public void removeListener(VoidCallback listener) {
this._repaint?.removeListener(listener);
}
public abstract void paint(Canvas canvas, Size size);
public abstract bool shouldRepaint(CustomPainter oldDelegate);
public virtual bool hitTest(Offset position) {
return false;
}
public override string ToString() {
return $"{Diagnostics.describeIdentity(this)}({this._repaint?.ToString() ?? ""})";
}
}
public class RenderCustomPaint : RenderProxyBox {
public RenderCustomPaint(
CustomPainter painter = null,
CustomPainter foregroundPainter = null,
Size preferredSize = null,
bool isComplex = false,
bool willChange = false,
RenderBox child = null
): base(child) {
preferredSize = preferredSize ?? Size.zero;
this.preferredSize = preferredSize;
this._painter = painter;
this._foregroundPainter = foregroundPainter;
this.isComplex = isComplex;
this.willChange = willChange;
}
CustomPainter _painter;
public CustomPainter painter {
get => this._painter;
set {
if (this._painter == value)
return;
CustomPainter oldPainter = this._painter;
this._painter = value;
this._didUpdatePainter(this._painter, oldPainter);
}
}
CustomPainter _foregroundPainter;
public CustomPainter foregroundPainter {
get => this._foregroundPainter;
set {
if (this._foregroundPainter == value)
return;
CustomPainter oldPainter = this._foregroundPainter;
this._foregroundPainter = value;
this._didUpdatePainter(this._foregroundPainter, oldPainter);
}
}
void _didUpdatePainter(CustomPainter newPainter, CustomPainter oldPainter) {
if (newPainter == null) {
D.assert(oldPainter != null);
this.markNeedsPaint();
}
else if (oldPainter == null ||
newPainter.GetType() != oldPainter.GetType() ||
newPainter.shouldRepaint(oldPainter)) {
this.markNeedsPaint();
}
if (this.attached) {
oldPainter?.removeListener(this.markNeedsPaint);
newPainter?.addListener(this.markNeedsPaint);
}
}
Size _preferredSize;
public Size preferredSize {
get => this._preferredSize;
set {
D.assert(value != null);
if (this.preferredSize == value)
return;
this._preferredSize = value;
this.markNeedsLayout();
}
}
public bool isComplex;
public bool willChange;
public override void attach(object owner) {
base.attach(owner);
this._painter?.addListener(this.markNeedsPaint);
this._foregroundPainter?.addListener(this.markNeedsPaint);
}
public override void detach() {
this._painter?.removeListener(this.markNeedsPaint);
this._foregroundPainter?.removeListener(this.markNeedsPaint);
base.detach();
}
protected override bool hitTestChildren(HitTestResult result, Offset position) {
if (this._foregroundPainter != null && (this._foregroundPainter.hitTest(position)))
return true;
return base.hitTestChildren(result, position: position);
}
protected override bool hitTestSelf(Offset position) {
return this._painter != null && this._painter.hitTest(position);
}
protected override void performResize() {
this.size = this.constraints.constrain(this.preferredSize);
}
void _paintWithPainter(Canvas canvas, Offset offset, CustomPainter painter) {
int debugPreviousCanvasSaveCount = 0;
canvas.save();
D.assert(() => {
debugPreviousCanvasSaveCount = canvas.getSaveCount();
return true;
});
if (offset != Offset.zero)
canvas.translate(offset.dx, offset.dy);
painter.paint(canvas, this.size);
D.assert(() => {
int debugNewCanvasSaveCount = canvas.getSaveCount();
if (debugNewCanvasSaveCount > debugPreviousCanvasSaveCount)
throw new UIWidgetsError(
$"{debugNewCanvasSaveCount - debugPreviousCanvasSaveCount} more " +
$"time{((debugNewCanvasSaveCount - debugPreviousCanvasSaveCount == 1) ? "" : "s")} " +
"than it called canvas.restore().\n" +
"This leaves the canvas in an inconsistent state and will probably result in a broken display.\n" +
"You must pair each call to save()/saveLayer() with a later matching call to restore()."
);
if (debugNewCanvasSaveCount < debugPreviousCanvasSaveCount)
throw new UIWidgetsError(
$"The {painter} custom painter called canvas.restore() " +
$"{debugPreviousCanvasSaveCount - debugNewCanvasSaveCount} more " +
$"time{(debugPreviousCanvasSaveCount - debugNewCanvasSaveCount == 1 ? "" : "s")} " +
"than it called canvas.save() or canvas.saveLayer().\n" +
"This leaves the canvas in an inconsistent state and will result in a broken display.\n" +
"You should only call restore() if you first called save() or saveLayer()."
);
return debugNewCanvasSaveCount == debugPreviousCanvasSaveCount;
});
canvas.restore();
}
public override void paint(PaintingContext context, Offset offset) {
if (this._painter != null) {
this._paintWithPainter(context.canvas, offset, this._painter);
this._setRasterCacheHints(context);
}
base.paint(context, offset);
if (this._foregroundPainter != null) {
this._paintWithPainter(context.canvas, offset, this._foregroundPainter);
this._setRasterCacheHints(context);
}
}
void _setRasterCacheHints(PaintingContext context) {
if (this.isComplex)
context.setIsComplexHint();
if (this.willChange)
context.setWillChangeHint();
}
}
}

11
Runtime/widgets/custom_paint.cs.meta


fileFormatVersion: 2
guid: a4b3c34c9775f4b9995fb37535490751
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

158
Runtime/widgets/navigation_toolbar.cs


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;
}
}
}

11
Runtime/widgets/navigation_toolbar.cs.meta


fileFormatVersion: 2
guid: 0d3291a5dbe68445896df6360fda57c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

69
Samples/UIWidgetSample/CustomPaintCanvas.cs


using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
namespace UIWidgetsSample {
public class CustomPaintCanvas: WidgetCanvas {
protected override Widget getWidget() {
return new CustomPaint(
child: new Container(width: 300, height: 300, color: new Color(0XFFFFFFFF)),
foregroundPainter: new GridPainter(null)
);
}
}
public class GridPainter : CustomPainter {
public GridPainter(Listenable repaint) : base(repaint) {
}
public override void paint(Canvas canvas, Size size) {
int numGrid = 4;
var paint = new Paint();
paint.color = new Color(0xFFFF0000);
paint.strokeWidth = 2;
paint.style = PaintingStyle.stroke;
for (int i = 1; i < numGrid; i++) {
double offsetY = size.height * i / numGrid;
canvas.drawLine(new Offset(0, offsetY), new Offset(size.width, offsetY),
paint);
}
for (int i = 1; i < numGrid; i++) {
double offsetx = size.width * i / numGrid;
canvas.drawLine(new Offset(offsetx, 0), new Offset(offsetx, size.height),
paint);
}
// draw a arrow line
canvas.save();
canvas.rotate(0.4);
canvas.scale(2, 2);
canvas.translate(50, 50);
canvas.drawLine(new Offset(0, 0), new Offset(100, 0),
new Paint(){
color = new Color(0xFFFF0000),
strokeWidth = 2,
style = PaintingStyle.stroke
});
var path = new Path();
var arrowPaint = new Paint() {
color = new Color(0xFFFF0000),
style = PaintingStyle.fill
};
path.moveTo(100, 0);
path.lineTo(100, 5);
path.lineTo(120, 0);
path.lineTo(100, -5);
path.close();
canvas.drawPath(path, arrowPaint);
canvas.restore();
}
public override bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
}

11
Samples/UIWidgetSample/CustomPaintCanvas.cs.meta


fileFormatVersion: 2
guid: 5debfd6de8ea942d487383a56aad8491
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存