Yuncong Zhang
6 年前
当前提交
98c48536
共有 42 个文件被更改,包括 6837 次插入 和 50 次删除
-
1Runtime/material/checkbox.cs
-
2Runtime/widgets/safe_area.cs
-
81Runtime/widgets/sliver.cs
-
70Runtime/widgets/sliver_persistent_header.cs
-
4Samples/UIWidgetsGallery/gallery/demo.cs
-
18Samples/UIWidgetsGallery/gallery/demos.cs
-
451Runtime/rendering/sliver_grid.cs
-
11Runtime/rendering/sliver_grid.cs.meta
-
553Runtime/widgets/heroes.cs
-
3Runtime/widgets/heroes.cs.meta
-
8Samples/UIWidgetsGallery/demo/shrine.meta
-
40Samples/UIWidgetsGallery/demo/shrine_demo.cs
-
3Samples/UIWidgetsGallery/demo/shrine_demo.cs.meta
-
8Tests/Resources/people.meta
-
280Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs
-
3Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs.meta
-
410Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs
-
11Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs.meta
-
343Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs
-
3Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs.meta
-
156Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs
-
3Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs.meta
-
98Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs
-
3Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs.meta
-
153Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs
-
3Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs.meta
-
1001Tests/Resources/people/ali_landscape.png
-
88Tests/Resources/people/ali_landscape.png.meta
-
8Tests/Resources/people/square.meta
-
457Tests/Resources/people/square/ali.png
-
88Tests/Resources/people/square/ali.png.meta
-
509Tests/Resources/people/square/peter.png
-
88Tests/Resources/people/square/peter.png.meta
-
698Tests/Resources/people/square/sandra.png
-
88Tests/Resources/people/square/sandra.png.meta
-
393Tests/Resources/people/square/stella.png
-
88Tests/Resources/people/square/stella.png.meta
-
574Tests/Resources/people/square/trevor.png
-
88Tests/Resources/people/square/trevor.png.meta
|
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace com.unity.uiwidgets.Runtime.rendering { |
|||
public class SliverGridGeometry { |
|||
public SliverGridGeometry( |
|||
float? scrollOffset = null, |
|||
float? crossAxisOffset = null, |
|||
float? mainAxisExtent = null, |
|||
float? crossAxisExtent = null |
|||
) { |
|||
this.scrollOffset = scrollOffset; |
|||
this.crossAxisOffset = crossAxisOffset; |
|||
this.mainAxisExtent = mainAxisExtent; |
|||
this.crossAxisExtent = crossAxisExtent; |
|||
} |
|||
|
|||
public readonly float? scrollOffset; |
|||
|
|||
public readonly float? crossAxisOffset; |
|||
|
|||
public readonly float? mainAxisExtent; |
|||
|
|||
public readonly float? crossAxisExtent; |
|||
|
|||
public float? trailingScrollOffset { |
|||
get { return this.scrollOffset + this.mainAxisExtent; } |
|||
} |
|||
|
|||
public BoxConstraints getBoxConstraints(SliverConstraints constraints) { |
|||
return constraints.asBoxConstraints( |
|||
minExtent: this.mainAxisExtent ?? 0.0f, |
|||
maxExtent: this.mainAxisExtent ?? 0.0f, |
|||
crossAxisExtent: this.crossAxisExtent ?? 0.0f |
|||
); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "SliverGridGeometry(" + |
|||
"scrollOffset: $scrollOffset, " + |
|||
"crossAxisOffset: $crossAxisOffset, " + |
|||
"mainAxisExtent: $mainAxisExtent, " + |
|||
"crossAxisExtent: $crossAxisExtent" + |
|||
")"; |
|||
} |
|||
} |
|||
|
|||
public abstract class SliverGridLayout { |
|||
public SliverGridLayout() { |
|||
} |
|||
|
|||
public abstract int getMinChildIndexForScrollOffset(float scrollOffset); |
|||
|
|||
public abstract int getMaxChildIndexForScrollOffset(float scrollOffset); |
|||
|
|||
public abstract SliverGridGeometry getGeometryForChildIndex(int index); |
|||
|
|||
public abstract float computeMaxScrollOffset(int childCount); |
|||
} |
|||
|
|||
public class SliverGridRegularTileLayout : SliverGridLayout { |
|||
public SliverGridRegularTileLayout( |
|||
int? crossAxisCount = null, |
|||
float? mainAxisStride = null, |
|||
float? crossAxisStride = null, |
|||
float? childMainAxisExtent = null, |
|||
float? childCrossAxisExtent = null, |
|||
bool? reverseCrossAxis = null |
|||
) { |
|||
D.assert(crossAxisCount != null && crossAxisCount > 0); |
|||
D.assert(mainAxisStride != null && mainAxisStride >= 0); |
|||
D.assert(crossAxisStride != null && crossAxisStride >= 0); |
|||
D.assert(childMainAxisExtent != null && childMainAxisExtent >= 0); |
|||
D.assert(childCrossAxisExtent != null && childCrossAxisExtent >= 0); |
|||
D.assert(reverseCrossAxis != null); |
|||
this.crossAxisCount = crossAxisCount; |
|||
this.mainAxisStride = mainAxisStride; |
|||
this.crossAxisStride = crossAxisStride; |
|||
this.childMainAxisExtent = childMainAxisExtent; |
|||
this.childCrossAxisExtent = childCrossAxisExtent; |
|||
this.reverseCrossAxis = reverseCrossAxis; |
|||
} |
|||
|
|||
public readonly int? crossAxisCount; |
|||
|
|||
public readonly float? mainAxisStride; |
|||
|
|||
public readonly float? crossAxisStride; |
|||
|
|||
public readonly float? childMainAxisExtent; |
|||
|
|||
public readonly float? childCrossAxisExtent; |
|||
|
|||
public readonly bool? reverseCrossAxis; |
|||
|
|||
public override int getMinChildIndexForScrollOffset(float scrollOffset) { |
|||
return (this.mainAxisStride > 0.0f |
|||
? this.crossAxisCount * ((int) (scrollOffset / this.mainAxisStride)) |
|||
: 0) ?? 0; |
|||
} |
|||
|
|||
public override int getMaxChildIndexForScrollOffset(float scrollOffset) { |
|||
if (this.mainAxisStride > 0.0f) { |
|||
int? mainAxisCount = (scrollOffset / this.mainAxisStride)?.ceil(); |
|||
return Mathf.Max(0, (this.crossAxisCount * mainAxisCount - 1) ?? 0); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
float _getOffsetFromStartInCrossAxis(float crossAxisStart) { |
|||
if (this.reverseCrossAxis == true) { |
|||
return (this.crossAxisCount * this.crossAxisStride - crossAxisStart - this.childCrossAxisExtent) ?? |
|||
0.0f; |
|||
} |
|||
|
|||
return crossAxisStart; |
|||
} |
|||
|
|||
public override SliverGridGeometry getGeometryForChildIndex(int index) { |
|||
float? crossAxisStart = (index % this.crossAxisCount) * this.crossAxisStride; |
|||
return new SliverGridGeometry( |
|||
scrollOffset: (index / this.crossAxisCount) * this.mainAxisStride, |
|||
crossAxisOffset: |
|||
this._getOffsetFromStartInCrossAxis(crossAxisStart ?? 0.0f), |
|||
mainAxisExtent: |
|||
this.childMainAxisExtent, |
|||
crossAxisExtent: |
|||
this.childCrossAxisExtent |
|||
); |
|||
} |
|||
|
|||
public override float computeMaxScrollOffset(int childCount) { |
|||
int? mainAxisCount = ((childCount - 1) / this.crossAxisCount) + 1; |
|||
float? mainAxisSpacing = this.mainAxisStride - this.childMainAxisExtent; |
|||
return (this.mainAxisStride * mainAxisCount - mainAxisSpacing) ?? 0.0f; |
|||
} |
|||
} |
|||
|
|||
public abstract class SliverGridDelegate { |
|||
public abstract SliverGridLayout getLayout(SliverConstraints constraints); |
|||
|
|||
public abstract bool shouldRelayout(SliverGridDelegate oldDelegate); |
|||
} |
|||
|
|||
public class SliverGridDelegateWithFixedCrossAxisCount : SliverGridDelegate { |
|||
public SliverGridDelegateWithFixedCrossAxisCount( |
|||
int crossAxisCount, |
|||
float mainAxisSpacing = 0.0f, |
|||
float crossAxisSpacing = 0.0f, |
|||
float childAspectRatio = 1.0f |
|||
) { |
|||
D.assert(crossAxisCount > 0); |
|||
D.assert(mainAxisSpacing >= 0); |
|||
D.assert(crossAxisSpacing >= 0); |
|||
D.assert(childAspectRatio > 0); |
|||
this.crossAxisCount = crossAxisCount; |
|||
this.mainAxisSpacing = mainAxisSpacing; |
|||
this.crossAxisSpacing = crossAxisSpacing; |
|||
this.childAspectRatio = childAspectRatio; |
|||
} |
|||
|
|||
public readonly int crossAxisCount; |
|||
|
|||
public readonly float mainAxisSpacing; |
|||
|
|||
public readonly float crossAxisSpacing; |
|||
|
|||
public readonly float childAspectRatio; |
|||
|
|||
bool _debugAssertIsValid() { |
|||
D.assert(this.crossAxisCount > 0); |
|||
D.assert(this.mainAxisSpacing >= 0.0f); |
|||
D.assert(this.crossAxisSpacing >= 0.0f); |
|||
D.assert(this.childAspectRatio > 0.0f); |
|||
return true; |
|||
} |
|||
|
|||
public override SliverGridLayout getLayout(SliverConstraints constraints) { |
|||
D.assert(this._debugAssertIsValid()); |
|||
float usableCrossAxisExtent = |
|||
constraints.crossAxisExtent - this.crossAxisSpacing * (this.crossAxisCount - 1); |
|||
float childCrossAxisExtent = usableCrossAxisExtent / this.crossAxisCount; |
|||
float childMainAxisExtent = childCrossAxisExtent / this.childAspectRatio; |
|||
return new SliverGridRegularTileLayout( |
|||
crossAxisCount: this.crossAxisCount, |
|||
mainAxisStride: childMainAxisExtent + this.mainAxisSpacing, |
|||
crossAxisStride: childCrossAxisExtent + this.crossAxisSpacing, |
|||
childMainAxisExtent: childMainAxisExtent, |
|||
childCrossAxisExtent: childCrossAxisExtent, |
|||
reverseCrossAxis: AxisUtils.axisDirectionIsReversed(constraints.crossAxisDirection) |
|||
); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SliverGridDelegate _oldDelegate) { |
|||
SliverGridDelegateWithFixedCrossAxisCount oldDelegate = |
|||
_oldDelegate as SliverGridDelegateWithFixedCrossAxisCount; |
|||
return oldDelegate.crossAxisCount != this.crossAxisCount |
|||
|| oldDelegate.mainAxisSpacing != this.mainAxisSpacing |
|||
|| oldDelegate.crossAxisSpacing != this.crossAxisSpacing |
|||
|| oldDelegate.childAspectRatio != this.childAspectRatio; |
|||
} |
|||
} |
|||
|
|||
public class SliverGridDelegateWithMaxCrossAxisExtent : SliverGridDelegate { |
|||
public SliverGridDelegateWithMaxCrossAxisExtent( |
|||
float maxCrossAxisExtent, |
|||
float mainAxisSpacing = 0.0f, |
|||
float crossAxisSpacing = 0.0f, |
|||
float childAspectRatio = 1.0f |
|||
) { |
|||
D.assert(maxCrossAxisExtent >= 0); |
|||
D.assert(mainAxisSpacing >= 0); |
|||
D.assert(crossAxisSpacing >= 0); |
|||
D.assert(childAspectRatio > 0); |
|||
this.maxCrossAxisExtent = maxCrossAxisExtent; |
|||
this.mainAxisSpacing = mainAxisSpacing; |
|||
this.crossAxisSpacing = crossAxisSpacing; |
|||
this.childAspectRatio = childAspectRatio; |
|||
} |
|||
|
|||
public readonly float maxCrossAxisExtent; |
|||
|
|||
public readonly float mainAxisSpacing; |
|||
|
|||
public readonly float crossAxisSpacing; |
|||
|
|||
public readonly float childAspectRatio; |
|||
|
|||
bool _debugAssertIsValid() { |
|||
D.assert(this.maxCrossAxisExtent > 0.0f); |
|||
D.assert(this.mainAxisSpacing >= 0.0f); |
|||
D.assert(this.crossAxisSpacing >= 0.0f); |
|||
D.assert(this.childAspectRatio > 0.0f); |
|||
return true; |
|||
} |
|||
|
|||
public override SliverGridLayout getLayout(SliverConstraints constraints) { |
|||
D.assert(this._debugAssertIsValid()); |
|||
int crossAxisCount = |
|||
(constraints.crossAxisExtent / (this.maxCrossAxisExtent + this.crossAxisSpacing)).ceil(); |
|||
float usableCrossAxisExtent = constraints.crossAxisExtent - this.crossAxisSpacing * (crossAxisCount - 1); |
|||
float childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount; |
|||
float childMainAxisExtent = childCrossAxisExtent / this.childAspectRatio; |
|||
return new SliverGridRegularTileLayout( |
|||
crossAxisCount: crossAxisCount, |
|||
mainAxisStride: childMainAxisExtent + this.mainAxisSpacing, |
|||
crossAxisStride: childCrossAxisExtent + this.crossAxisSpacing, |
|||
childMainAxisExtent: childMainAxisExtent, |
|||
childCrossAxisExtent: childCrossAxisExtent, |
|||
reverseCrossAxis: AxisUtils.axisDirectionIsReversed(constraints.crossAxisDirection) |
|||
); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SliverGridDelegate _oldDelegate) { |
|||
SliverGridDelegateWithMaxCrossAxisExtent oldDelegate = |
|||
_oldDelegate as SliverGridDelegateWithMaxCrossAxisExtent; |
|||
return oldDelegate.maxCrossAxisExtent != this.maxCrossAxisExtent |
|||
|| oldDelegate.mainAxisSpacing != this.mainAxisSpacing |
|||
|| oldDelegate.crossAxisSpacing != this.crossAxisSpacing |
|||
|| oldDelegate.childAspectRatio != this.childAspectRatio; |
|||
} |
|||
} |
|||
|
|||
public class SliverGridParentData : SliverMultiBoxAdaptorParentData { |
|||
public float crossAxisOffset; |
|||
|
|||
public override string ToString() { |
|||
return "crossAxisOffset=$crossAxisOffset; ${base.ToString()}"; |
|||
} |
|||
} |
|||
|
|||
public class RenderSliverGrid : RenderSliverMultiBoxAdaptor { |
|||
public RenderSliverGrid( |
|||
RenderSliverBoxChildManager childManager, |
|||
SliverGridDelegate gridDelegate |
|||
) : base(childManager: childManager) { |
|||
D.assert(gridDelegate != null); |
|||
this._gridDelegate = gridDelegate; |
|||
} |
|||
|
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is SliverGridParentData)) { |
|||
child.parentData = new SliverGridParentData(); |
|||
} |
|||
} |
|||
|
|||
public SliverGridDelegate gridDelegate { |
|||
get { return this._gridDelegate; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (this._gridDelegate == value) { |
|||
return; |
|||
} |
|||
|
|||
if (value.GetType() != this._gridDelegate.GetType() || |
|||
value.shouldRelayout(this._gridDelegate)) { |
|||
this.markNeedsLayout(); |
|||
} |
|||
|
|||
this._gridDelegate = value; |
|||
} |
|||
} |
|||
|
|||
SliverGridDelegate _gridDelegate; |
|||
|
|||
public override float childCrossAxisPosition(RenderObject child) { |
|||
SliverGridParentData childParentData = (SliverGridParentData) child.parentData; |
|||
return childParentData.crossAxisOffset; |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
this.childManager.didStartLayout(); |
|||
this.childManager.setDidUnderflow(false); |
|||
|
|||
float scrollOffset = this.constraints.scrollOffset + this.constraints.cacheOrigin; |
|||
D.assert(scrollOffset >= 0.0f); |
|||
float remainingExtent = this.constraints.remainingCacheExtent; |
|||
D.assert(remainingExtent >= 0.0f); |
|||
float targetEndScrollOffset = scrollOffset + remainingExtent; |
|||
|
|||
SliverGridLayout layout = this._gridDelegate.getLayout(this.constraints); |
|||
|
|||
int firstIndex = layout.getMinChildIndexForScrollOffset(scrollOffset); |
|||
int? targetLastIndex = targetEndScrollOffset.isFinite() |
|||
? (int?) layout.getMaxChildIndexForScrollOffset(targetEndScrollOffset) |
|||
: null; |
|||
|
|||
if (this.firstChild != null) { |
|||
int oldFirstIndex = this.indexOf(this.firstChild); |
|||
int oldLastIndex = this.indexOf(this.lastChild); |
|||
int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, this.childCount); |
|||
int trailingGarbage = targetLastIndex == null |
|||
? 0 |
|||
: ((oldLastIndex - targetLastIndex) ?? 0).clamp(0, this.childCount); |
|||
this.collectGarbage(leadingGarbage, trailingGarbage); |
|||
} |
|||
else { |
|||
this.collectGarbage(0, 0); |
|||
} |
|||
|
|||
SliverGridGeometry firstChildGridGeometry = layout.getGeometryForChildIndex(firstIndex); |
|||
float? leadingScrollOffset = firstChildGridGeometry.scrollOffset; |
|||
float? trailingScrollOffset = firstChildGridGeometry.trailingScrollOffset; |
|||
|
|||
if (this.firstChild == null) { |
|||
if (!this.addInitialChild(index: firstIndex, |
|||
layoutOffset: firstChildGridGeometry.scrollOffset ?? 0.0f)) { |
|||
float max = layout.computeMaxScrollOffset(this.childManager.childCount ?? 0); |
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: max, |
|||
maxPaintExtent: max |
|||
); |
|||
this.childManager.didFinishLayout(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
RenderBox trailingChildWithLayout = null; |
|||
|
|||
for (int index = this.indexOf(this.firstChild) - 1; index >= firstIndex; --index) { |
|||
SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index); |
|||
RenderBox child = this.insertAndLayoutLeadingChild( |
|||
gridGeometry.getBoxConstraints(this.constraints) |
|||
); |
|||
SliverGridParentData childParentData = child.parentData as SliverGridParentData; |
|||
childParentData.layoutOffset = gridGeometry.scrollOffset ?? 0.0f; |
|||
childParentData.crossAxisOffset = gridGeometry.crossAxisOffset ?? 0.0f; |
|||
D.assert(childParentData.index == index); |
|||
trailingChildWithLayout = trailingChildWithLayout ?? child; |
|||
trailingScrollOffset = |
|||
Mathf.Max(trailingScrollOffset ?? 0.0f, gridGeometry.trailingScrollOffset ?? 0.0f); |
|||
} |
|||
|
|||
if (trailingChildWithLayout == null) { |
|||
this.firstChild.layout(firstChildGridGeometry.getBoxConstraints(this.constraints)); |
|||
SliverGridParentData childParentData = this.firstChild.parentData as SliverGridParentData; |
|||
childParentData.layoutOffset = firstChildGridGeometry.scrollOffset ?? 0.0f; |
|||
childParentData.crossAxisOffset = firstChildGridGeometry.crossAxisOffset ?? 0.0f; |
|||
trailingChildWithLayout = this.firstChild; |
|||
} |
|||
|
|||
for (int index = this.indexOf(trailingChildWithLayout) + 1; |
|||
targetLastIndex == null || index <= targetLastIndex; |
|||
++index) { |
|||
SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index); |
|||
BoxConstraints childConstraints = gridGeometry.getBoxConstraints(this.constraints); |
|||
RenderBox child = this.childAfter(trailingChildWithLayout); |
|||
if (child == null) { |
|||
child = this.insertAndLayoutChild(childConstraints, after: trailingChildWithLayout); |
|||
if (child == null) { |
|||
break; |
|||
} |
|||
} |
|||
else { |
|||
child.layout(childConstraints); |
|||
} |
|||
|
|||
trailingChildWithLayout = child; |
|||
D.assert(child != null); |
|||
SliverGridParentData childParentData = child.parentData as SliverGridParentData; |
|||
childParentData.layoutOffset = gridGeometry.scrollOffset ?? 0.0f; |
|||
childParentData.crossAxisOffset = gridGeometry.crossAxisOffset ?? 0.0f; |
|||
D.assert(childParentData.index == index); |
|||
trailingScrollOffset = |
|||
Mathf.Max(trailingScrollOffset ?? 0.0f, gridGeometry.trailingScrollOffset ?? 0.0f); |
|||
} |
|||
|
|||
int lastIndex = this.indexOf(this.lastChild); |
|||
|
|||
D.assert(this.childScrollOffset(this.firstChild) <= scrollOffset); |
|||
D.assert(this.debugAssertChildListIsNonEmptyAndContiguous()); |
|||
D.assert(this.indexOf(this.firstChild) == firstIndex); |
|||
D.assert(targetLastIndex == null || lastIndex <= targetLastIndex); |
|||
|
|||
float estimatedTotalExtent = this.childManager.estimateMaxScrollOffset(this.constraints, |
|||
firstIndex: firstIndex, |
|||
lastIndex: lastIndex, |
|||
leadingScrollOffset: leadingScrollOffset ?? 0.0f, |
|||
trailingScrollOffset: trailingScrollOffset ?? 0.0f |
|||
); |
|||
|
|||
float paintExtent = this.calculatePaintOffset(this.constraints, |
|||
from: leadingScrollOffset ?? 0.0f, |
|||
to: trailingScrollOffset ?? 0.0f |
|||
); |
|||
float cacheExtent = this.calculateCacheOffset(this.constraints, |
|||
from: leadingScrollOffset ?? 0.0f, |
|||
to: trailingScrollOffset ?? 0.0f |
|||
); |
|||
|
|||
this.geometry = new SliverGeometry( |
|||
scrollExtent: estimatedTotalExtent, |
|||
paintExtent: paintExtent, |
|||
maxPaintExtent: estimatedTotalExtent, |
|||
cacheExtent: cacheExtent, |
|||
hasVisualOverflow: true |
|||
); |
|||
|
|||
if (estimatedTotalExtent == trailingScrollOffset) { |
|||
this.childManager.setDidUnderflow(true); |
|||
} |
|||
|
|||
this.childManager.didFinishLayout(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5ba43ca1896804e9b8ca548384ee2abc |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public delegate Tween<Rect> CreateRectTween(Rect begin, Rect end); |
|||
|
|||
public delegate Widget HeroFlightShuttleBuilder( |
|||
BuildContext flightContext, |
|||
Animation<float> animation, |
|||
HeroFlightDirection flightDirection, |
|||
BuildContext fromHeroContext, |
|||
BuildContext toHeroContext |
|||
); |
|||
|
|||
delegate void _OnFlightEnded(_HeroFlight flight); |
|||
|
|||
public enum HeroFlightDirection { |
|||
push, |
|||
pop |
|||
} |
|||
|
|||
class HeroUtils { |
|||
public static Rect _globalBoundingBoxFor(BuildContext context) { |
|||
RenderBox box = (RenderBox) context.findRenderObject(); |
|||
D.assert(box != null && box.hasSize); |
|||
return box.getTransformTo(null).mapRect(Offset.zero & box.size); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class Hero : StatefulWidget { |
|||
public Hero( |
|||
Key key = null, |
|||
object tag = null, |
|||
CreateRectTween createRectTween = null, |
|||
HeroFlightShuttleBuilder flightShuttleBuilder = null, |
|||
TransitionBuilder placeholderBuilder = null, |
|||
bool transitionOnUserGestures = false, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
D.assert(tag != null); |
|||
D.assert(child != null); |
|||
this.tag = tag; |
|||
this.createRectTween = createRectTween; |
|||
this.child = child; |
|||
this.flightShuttleBuilder = flightShuttleBuilder; |
|||
this.placeholderBuilder = placeholderBuilder; |
|||
this.transitionOnUserGestures = transitionOnUserGestures; |
|||
} |
|||
|
|||
|
|||
public readonly object tag; |
|||
|
|||
public readonly CreateRectTween createRectTween; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly HeroFlightShuttleBuilder flightShuttleBuilder; |
|||
|
|||
public readonly TransitionBuilder placeholderBuilder; |
|||
|
|||
public readonly bool transitionOnUserGestures; |
|||
|
|||
internal static Dictionary<object, _HeroState> |
|||
_allHeroesFor(BuildContext context, bool isUserGestureTransition) { |
|||
D.assert(context != null); |
|||
Dictionary<object, _HeroState> result = new Dictionary<object, _HeroState> { }; |
|||
|
|||
void visitor(Element element) { |
|||
if (element.widget is Hero) { |
|||
StatefulElement hero = (StatefulElement) element; |
|||
Hero heroWidget = (Hero) element.widget; |
|||
if (!isUserGestureTransition || heroWidget.transitionOnUserGestures) { |
|||
object tag = heroWidget.tag; |
|||
D.assert(tag != null); |
|||
D.assert(() => { |
|||
if (result.ContainsKey(tag)) { |
|||
throw new UIWidgetsError( |
|||
"There are multiple heroes that share the same tag within a subtree.\n" + |
|||
"Within each subtree for which heroes are to be animated (typically a PageRoute subtree), " + |
|||
"each Hero must have a unique non-null tag.\n" + |
|||
$"In this case, multiple heroes had the following tag: {tag}\n" + |
|||
"Here is the subtree for one of the offending heroes:\n" + |
|||
$"{element.toStringDeep(prefixLineOne: "# ")}" |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
_HeroState heroState = (_HeroState) hero.state; |
|||
result[tag] = heroState; |
|||
} |
|||
} |
|||
|
|||
element.visitChildren(visitor); |
|||
} |
|||
|
|||
context.visitChildElements(visitor); |
|||
return result; |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _HeroState(); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new DiagnosticsProperty<object>("tag", this.tag)); |
|||
} |
|||
} |
|||
|
|||
class _HeroState : State<Hero> { |
|||
GlobalKey _key = GlobalKey.key(); |
|||
Size _placeholderSize; |
|||
|
|||
public void startFlight() { |
|||
D.assert(this.mounted); |
|||
RenderBox box = (RenderBox) this.context.findRenderObject(); |
|||
D.assert(box != null && box.hasSize); |
|||
this.setState(() => { this._placeholderSize = box.size; }); |
|||
} |
|||
|
|||
public void endFlight() { |
|||
if (this.mounted) { |
|||
this.setState(() => { this._placeholderSize = null; }); |
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
if (this._placeholderSize != null) { |
|||
if (this.widget.placeholderBuilder == null) { |
|||
return new SizedBox( |
|||
width: this._placeholderSize.width, |
|||
height: this._placeholderSize.height |
|||
); |
|||
} |
|||
else { |
|||
return this.widget.placeholderBuilder(context, this.widget.child); |
|||
} |
|||
} |
|||
|
|||
return new KeyedSubtree( |
|||
key: this._key, |
|||
child: this.widget.child |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _HeroFlightManifest { |
|||
public _HeroFlightManifest( |
|||
HeroFlightDirection type, |
|||
OverlayState overlay, |
|||
Rect navigatorRect, |
|||
PageRoute fromRoute, |
|||
PageRoute toRoute, |
|||
_HeroState fromHero, |
|||
_HeroState toHero, |
|||
CreateRectTween createRectTween, |
|||
HeroFlightShuttleBuilder shuttleBuilder, |
|||
bool isUserGestureTransition |
|||
) { |
|||
D.assert(this.fromHero.widget.tag == this.toHero.widget.tag); |
|||
this.type = type; |
|||
this.overlay = overlay; |
|||
this.navigatorRect = navigatorRect; |
|||
this.fromRoute = fromRoute; |
|||
this.toRoute = toRoute; |
|||
this.fromHero = fromHero; |
|||
this.toHero = toHero; |
|||
this.createRectTween = createRectTween; |
|||
this.shuttleBuilder = shuttleBuilder; |
|||
this.isUserGestureTransition = isUserGestureTransition; |
|||
} |
|||
|
|||
public readonly HeroFlightDirection type; |
|||
public readonly OverlayState overlay; |
|||
public readonly Rect navigatorRect; |
|||
public readonly PageRoute fromRoute; |
|||
public readonly PageRoute toRoute; |
|||
public readonly _HeroState fromHero; |
|||
public readonly _HeroState toHero; |
|||
public readonly CreateRectTween createRectTween; |
|||
public readonly HeroFlightShuttleBuilder shuttleBuilder; |
|||
public readonly bool isUserGestureTransition; |
|||
|
|||
public object tag { |
|||
get { return this.fromHero.widget.tag; } |
|||
} |
|||
|
|||
public Animation<float> animation { |
|||
get { |
|||
return new CurvedAnimation( |
|||
parent: (this.type == HeroFlightDirection.push) ? this.toRoute.animation : this.fromRoute.animation, |
|||
curve: Curves.fastOutSlowIn |
|||
); |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return $"_HeroFlightManifest($type tag: $tag from route: {this.fromRoute.settings} " + |
|||
$"to route: {this.toRoute.settings} with hero: {this.fromHero} to {this.toHero})"; |
|||
} |
|||
} |
|||
|
|||
class _HeroFlight { |
|||
public _HeroFlight(_OnFlightEnded onFlightEnded) { |
|||
this.onFlightEnded = onFlightEnded; |
|||
this._proxyAnimation = new ProxyAnimation(); |
|||
this._proxyAnimation.addStatusListener(this._handleAnimationUpdate); |
|||
} |
|||
|
|||
public readonly _OnFlightEnded onFlightEnded; |
|||
|
|||
Tween<Rect> heroRectTween; |
|||
Widget shuttle; |
|||
|
|||
Animation<float> _heroOpacity = Animations.kAlwaysCompleteAnimation; |
|||
ProxyAnimation _proxyAnimation; |
|||
public _HeroFlightManifest manifest; |
|||
public OverlayEntry overlayEntry; |
|||
bool _aborted = false; |
|||
|
|||
Tween<Rect> _doCreateRectTween(Rect begin, Rect end) { |
|||
CreateRectTween createRectTween = |
|||
this.manifest.toHero.widget.createRectTween ?? this.manifest.createRectTween; |
|||
if (createRectTween != null) { |
|||
return createRectTween(begin, end); |
|||
} |
|||
|
|||
return new RectTween(begin: begin, end: end); |
|||
} |
|||
|
|||
static readonly Animatable<float> _reverseTween = new FloatTween(begin: 1.0f, end: 0.0f); |
|||
|
|||
Widget _buildOverlay(BuildContext context) { |
|||
D.assert(this.manifest != null); |
|||
this.shuttle = this.shuttle ?? this.manifest.shuttleBuilder( |
|||
context, this.manifest.animation, this.manifest.type, this.manifest.fromHero.context, |
|||
this.manifest.toHero.context |
|||
); |
|||
D.assert(this.shuttle != null); |
|||
|
|||
return new AnimatedBuilder( |
|||
animation: this._proxyAnimation, |
|||
child: this.shuttle, |
|||
builder: (BuildContext _, Widget child) => { |
|||
RenderBox toHeroBox = (RenderBox) this.manifest.toHero.context?.findRenderObject(); |
|||
if (this._aborted || toHeroBox == null || !toHeroBox.attached) { |
|||
if (this._heroOpacity.isCompleted) { |
|||
this._heroOpacity = this._proxyAnimation.drive( |
|||
_reverseTween.chain( |
|||
new CurveTween(curve: new Interval(this._proxyAnimation.value, 1.0f))) |
|||
); |
|||
} |
|||
} |
|||
else if (toHeroBox.hasSize) { |
|||
RenderBox finalRouteBox = (RenderBox) this.manifest.toRoute.subtreeContext?.findRenderObject(); |
|||
Offset toHeroOrigin = toHeroBox.localToGlobal(Offset.zero, ancestor: finalRouteBox); |
|||
if (toHeroOrigin != this.heroRectTween.end.topLeft) { |
|||
Rect heroRectEnd = toHeroOrigin & this.heroRectTween.end.size; |
|||
this.heroRectTween = this._doCreateRectTween(this.heroRectTween.begin, heroRectEnd); |
|||
} |
|||
} |
|||
|
|||
Rect rect = this.heroRectTween.evaluate(this._proxyAnimation); |
|||
Size size = this.manifest.navigatorRect.size; |
|||
RelativeRect offsets = RelativeRect.fromSize(rect, size); |
|||
|
|||
return new Positioned( |
|||
top: offsets.top, |
|||
right: offsets.right, |
|||
bottom: offsets.bottom, |
|||
left: offsets.left, |
|||
child: new IgnorePointer( |
|||
child: new RepaintBoundary( |
|||
child: new Opacity( |
|||
opacity: this._heroOpacity.value, |
|||
child: child |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
); |
|||
} |
|||
|
|||
void _handleAnimationUpdate(AnimationStatus status) { |
|||
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { |
|||
this._proxyAnimation.parent = null; |
|||
|
|||
D.assert(this.overlayEntry != null); |
|||
this.overlayEntry.remove(); |
|||
this.overlayEntry = null; |
|||
|
|||
this.manifest.fromHero.endFlight(); |
|||
this.manifest.toHero.endFlight(); |
|||
this.onFlightEnded(this); |
|||
} |
|||
} |
|||
|
|||
public void start(_HeroFlightManifest initialManifest) { |
|||
D.assert(!this._aborted); |
|||
D.assert(() => { |
|||
Animation<float> initial = initialManifest.animation; |
|||
D.assert(initial != null); |
|||
HeroFlightDirection type = initialManifest.type; |
|||
switch (type) { |
|||
case HeroFlightDirection.pop: |
|||
return initial.value == 1.0f && initialManifest.isUserGestureTransition |
|||
? initial.status == AnimationStatus.completed |
|||
: initial.status == AnimationStatus.reverse; |
|||
case HeroFlightDirection.push: |
|||
return initial.value == 0.0f && initial.status == AnimationStatus.forward; |
|||
} |
|||
|
|||
throw new Exception("Unknown type: " + type); |
|||
}); |
|||
|
|||
this.manifest = initialManifest; |
|||
|
|||
if (this.manifest.type == HeroFlightDirection.pop) { |
|||
this._proxyAnimation.parent = new ReverseAnimation(this.manifest.animation); |
|||
} |
|||
else { |
|||
this._proxyAnimation.parent = this.manifest.animation; |
|||
} |
|||
|
|||
this.manifest.fromHero.startFlight(); |
|||
this.manifest.toHero.startFlight(); |
|||
|
|||
this.heroRectTween = this._doCreateRectTween( |
|||
HeroUtils._globalBoundingBoxFor(this.manifest.fromHero.context), |
|||
HeroUtils._globalBoundingBoxFor(this.manifest.toHero.context) |
|||
); |
|||
|
|||
this.overlayEntry = new OverlayEntry(builder: this._buildOverlay); |
|||
this.manifest.overlay.insert(this.overlayEntry); |
|||
} |
|||
|
|||
public void divert(_HeroFlightManifest newManifest) { |
|||
D.assert(this.manifest.tag == newManifest.tag); |
|||
|
|||
if (this.manifest.type == HeroFlightDirection.push && newManifest.type == HeroFlightDirection.pop) { |
|||
D.assert(newManifest.animation.status == AnimationStatus.reverse); |
|||
D.assert(this.manifest.fromHero == newManifest.toHero); |
|||
D.assert(this.manifest.toHero == newManifest.fromHero); |
|||
D.assert(this.manifest.fromRoute == newManifest.toRoute); |
|||
D.assert(this.manifest.toRoute == newManifest.fromRoute); |
|||
|
|||
this._proxyAnimation.parent = new ReverseAnimation(newManifest.animation); |
|||
this.heroRectTween = new ReverseTween<Rect>(this.heroRectTween); |
|||
} |
|||
else if (this.manifest.type == HeroFlightDirection.pop && newManifest.type == HeroFlightDirection.push) { |
|||
D.assert(newManifest.animation.status == AnimationStatus.forward); |
|||
D.assert(this.manifest.toHero == newManifest.fromHero); |
|||
D.assert(this.manifest.toRoute == newManifest.fromRoute); |
|||
|
|||
this._proxyAnimation.parent = newManifest.animation.drive( |
|||
new FloatTween( |
|||
begin: this.manifest.animation.value, |
|||
end: 1.0f |
|||
) |
|||
); |
|||
|
|||
if (this.manifest.fromHero != newManifest.toHero) { |
|||
this.manifest.fromHero.endFlight(); |
|||
newManifest.toHero.startFlight(); |
|||
this.heroRectTween = this._doCreateRectTween(this.heroRectTween.end, |
|||
HeroUtils._globalBoundingBoxFor(newManifest.toHero.context)); |
|||
} |
|||
else { |
|||
this.heroRectTween = this._doCreateRectTween(this.heroRectTween.end, this.heroRectTween.begin); |
|||
} |
|||
} |
|||
else { |
|||
D.assert(this.manifest.fromHero != newManifest.fromHero); |
|||
D.assert(this.manifest.toHero != newManifest.toHero); |
|||
|
|||
this.heroRectTween = this._doCreateRectTween(this.heroRectTween.evaluate(this._proxyAnimation), |
|||
HeroUtils._globalBoundingBoxFor(newManifest.toHero.context)); |
|||
this.shuttle = null; |
|||
|
|||
if (newManifest.type == HeroFlightDirection.pop) { |
|||
this._proxyAnimation.parent = new ReverseAnimation(newManifest.animation); |
|||
} |
|||
else { |
|||
this._proxyAnimation.parent = newManifest.animation; |
|||
} |
|||
|
|||
this.manifest.fromHero.endFlight(); |
|||
this.manifest.toHero.endFlight(); |
|||
|
|||
newManifest.fromHero.startFlight(); |
|||
newManifest.toHero.startFlight(); |
|||
|
|||
this.overlayEntry.markNeedsBuild(); |
|||
} |
|||
|
|||
this._aborted = false; |
|||
this.manifest = newManifest; |
|||
} |
|||
|
|||
public void abort() { |
|||
this._aborted = true; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
RouteSettings from = this.manifest.fromRoute.settings; |
|||
RouteSettings to = this.manifest.toRoute.settings; |
|||
object tag = this.manifest.tag; |
|||
return "HeroFlight(for: $tag, from: $from, to: $to ${_proxyAnimation.parent})"; |
|||
} |
|||
} |
|||
|
|||
public class HeroController : NavigatorObserver { |
|||
HeroController(CreateRectTween createRectTween) { |
|||
this.createRectTween = createRectTween; |
|||
} |
|||
|
|||
public readonly CreateRectTween createRectTween; |
|||
|
|||
Dictionary<object, _HeroFlight> _flights = new Dictionary<object, _HeroFlight>(); |
|||
|
|||
public override void didPush(Route route, Route previousRoute) { |
|||
D.assert(this.navigator != null); |
|||
D.assert(route != null); |
|||
this._maybeStartHeroTransition(previousRoute, route, HeroFlightDirection.push, false); |
|||
} |
|||
|
|||
public override void didPop(Route route, Route previousRoute) { |
|||
D.assert(this.navigator != null); |
|||
D.assert(route != null); |
|||
this._maybeStartHeroTransition(route, previousRoute, HeroFlightDirection.pop, false); |
|||
} |
|||
|
|||
public override void didStartUserGesture(Route route, Route previousRoute) { |
|||
D.assert(this.navigator != null); |
|||
D.assert(route != null); |
|||
this._maybeStartHeroTransition(route, previousRoute, HeroFlightDirection.pop, true); |
|||
} |
|||
|
|||
void _maybeStartHeroTransition( |
|||
Route fromRoute, |
|||
Route toRoute, |
|||
HeroFlightDirection flightType, |
|||
bool isUserGestureTransition |
|||
) { |
|||
if (toRoute != fromRoute && toRoute is PageRoute && fromRoute is PageRoute) { |
|||
PageRoute from = (PageRoute) fromRoute; |
|||
PageRoute to = (PageRoute) toRoute; |
|||
Animation<float> animation = (flightType == HeroFlightDirection.push) ? to.animation : from.animation; |
|||
|
|||
switch (flightType) { |
|||
case HeroFlightDirection.pop: |
|||
if (animation.value == 0.0f) { |
|||
return; |
|||
} |
|||
|
|||
break; |
|||
case HeroFlightDirection.push: |
|||
if (animation.value == 1.0f) { |
|||
return; |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
if (isUserGestureTransition && flightType == HeroFlightDirection.pop && to.maintainState) { |
|||
this._startHeroTransition(from, to, animation, flightType, isUserGestureTransition); |
|||
} |
|||
else { |
|||
to.offstage = to.animation.value == 0.0f; |
|||
|
|||
WidgetsBinding.instance.addPostFrameCallback((TimeSpan value) => { |
|||
this._startHeroTransition(from, to, animation, flightType, isUserGestureTransition); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _startHeroTransition( |
|||
PageRoute from, |
|||
PageRoute to, |
|||
Animation<float> animation, |
|||
HeroFlightDirection flightType, |
|||
bool isUserGestureTransition |
|||
) { |
|||
if (this.navigator == null || from.subtreeContext == null || to.subtreeContext == null) { |
|||
to.offstage = false; // in case we set this in _maybeStartHeroTransition
|
|||
return; |
|||
} |
|||
|
|||
Rect navigatorRect = HeroUtils._globalBoundingBoxFor(this.navigator.context); |
|||
|
|||
Dictionary<object, _HeroState> |
|||
fromHeroes = Hero._allHeroesFor(from.subtreeContext, isUserGestureTransition); |
|||
Dictionary<object, _HeroState> toHeroes = Hero._allHeroesFor(to.subtreeContext, isUserGestureTransition); |
|||
|
|||
to.offstage = false; |
|||
|
|||
foreach (object tag in fromHeroes.Keys) { |
|||
if (toHeroes[tag] != null) { |
|||
HeroFlightShuttleBuilder fromShuttleBuilder = fromHeroes[tag].widget.flightShuttleBuilder; |
|||
HeroFlightShuttleBuilder toShuttleBuilder = toHeroes[tag].widget.flightShuttleBuilder; |
|||
|
|||
_HeroFlightManifest manifest = new _HeroFlightManifest( |
|||
type: flightType, |
|||
overlay: this.navigator.overlay, |
|||
navigatorRect: navigatorRect, |
|||
fromRoute: from, |
|||
toRoute: to, |
|||
fromHero: fromHeroes[tag], |
|||
toHero: toHeroes[tag], |
|||
createRectTween: this.createRectTween, |
|||
shuttleBuilder: |
|||
toShuttleBuilder ?? fromShuttleBuilder ?? _defaultHeroFlightShuttleBuilder, |
|||
isUserGestureTransition: isUserGestureTransition |
|||
); |
|||
|
|||
if (this._flights[tag] != null) { |
|||
this._flights[tag].divert(manifest); |
|||
} |
|||
else { |
|||
this._flights[tag] = new _HeroFlight(this._handleFlightEnded); |
|||
this._flights[tag].start(manifest); |
|||
} |
|||
} |
|||
else if (this._flights[tag] != null) { |
|||
this._flights[tag].abort(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _handleFlightEnded(_HeroFlight flight) { |
|||
this._flights.Remove(flight.manifest.tag); |
|||
} |
|||
|
|||
static readonly HeroFlightShuttleBuilder _defaultHeroFlightShuttleBuilder = ( |
|||
BuildContext flightContext, |
|||
Animation<float> animation, |
|||
HeroFlightDirection flightDirection, |
|||
BuildContext fromHeroContext, |
|||
BuildContext toHeroContext |
|||
) => { |
|||
Hero toHero = (Hero) toHeroContext.widget; |
|||
return toHero.child; |
|||
}; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ae21d125110c4c989fd2ce9e5a0bc1c0 |
|||
timeCreated: 1554263028 |
|
|||
fileFormatVersion: 2 |
|||
guid: 2621a6f94ad8a4b5ab7199025967dc90 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class ShrineDemoUtils { |
|||
public static Widget buildShrine(BuildContext context, Widget child) { |
|||
return new Theme( |
|||
data: new ThemeData( |
|||
primarySwatch: Colors.grey, |
|||
iconTheme: new IconThemeData(color: new Color(0xFF707070)), |
|||
platform: Theme.of(context).platform |
|||
), |
|||
child: new ShrineTheme(child: child) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class ShrinePageRoute<T> : MaterialPageRoute { |
|||
public ShrinePageRoute( |
|||
WidgetBuilder builder, |
|||
RouteSettings settings |
|||
) : base(builder: builder, settings: settings) { |
|||
} |
|||
|
|||
public override Widget buildPage(BuildContext context, Animation<float> animation, |
|||
Animation<float> secondaryAnimation) { |
|||
return ShrineDemoUtils.buildShrine(context, base.buildPage(context, animation, secondaryAnimation)); |
|||
} |
|||
} |
|||
|
|||
public class ShrineDemo : StatelessWidget { |
|||
public const string routeName = "/shrine"; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return ShrineDemoUtils.buildShrine(context, new ShrineHome()); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5902905cca7447d2aa1fe5ae7f6c5cbc |
|||
timeCreated: 1553239620 |
|
|||
fileFormatVersion: 2 |
|||
guid: 8988da6435b0e414da67d5bb45802754 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.foundation; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class ShrineData { |
|||
const string _kGalleryAssetsPackage = "flutter_gallery_assets"; |
|||
|
|||
static Vendor _ali = new Vendor( |
|||
name: "Ali’s shop", |
|||
avatarAsset: "people/square/ali", |
|||
avatarAssetPackage: _kGalleryAssetsPackage, |
|||
description: |
|||
"Ali Connor’s makes custom goods for folks of all shapes and sizes " + |
|||
"made by hand and sometimes by machine, but always with love and care. " + |
|||
"Custom orders are available upon request if you need something extra special." |
|||
); |
|||
|
|||
static Vendor _peter = new Vendor( |
|||
name: "Peter’s shop", |
|||
avatarAsset: "people/square/peter", |
|||
avatarAssetPackage: _kGalleryAssetsPackage, |
|||
description: |
|||
"Peter makes great stuff for awesome people like you. Super cool and extra " + |
|||
"awesome all of his shop’s goods are handmade with love. Custom orders are " + |
|||
"available upon request if you need something extra special." |
|||
); |
|||
|
|||
static Vendor _sandra = new Vendor( |
|||
name: "Sandra’s shop", |
|||
avatarAsset: "people/square/sandra", |
|||
avatarAssetPackage: _kGalleryAssetsPackage, |
|||
description: |
|||
"Sandra specializes in furniture, beauty and travel products with a classic vibe. " + |
|||
"Custom orders are available if you’re looking for a certain color or material." |
|||
); |
|||
|
|||
static Vendor _stella = new Vendor( |
|||
name: "Stella’s shop", |
|||
avatarAsset: "people/square/stella", |
|||
avatarAssetPackage: _kGalleryAssetsPackage, |
|||
description: |
|||
"Stella sells awesome stuff at lovely prices. made by hand and sometimes by " + |
|||
"machine, but always with love and care. Custom orders are available upon request " + |
|||
"if you need something extra special." |
|||
); |
|||
|
|||
static Vendor _trevor = new Vendor( |
|||
name: "Trevor’s shop", |
|||
avatarAsset: "people/square/trevor", |
|||
avatarAssetPackage: _kGalleryAssetsPackage, |
|||
description: |
|||
"Trevor makes great stuff for awesome people like you. Super cool and extra " + |
|||
"awesome all of his shop’s goods are handmade with love. Custom orders are " + |
|||
"available upon request if you need something extra special." |
|||
); |
|||
|
|||
static readonly List<Product> _allProducts = new List<Product> { |
|||
new Product( |
|||
name: "Vintage Brown Belt", |
|||
imageAsset: "products/belt", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion", "latest"}, |
|||
price: 300.00f, |
|||
vendor: _sandra, |
|||
description: |
|||
"Isn’t it cool when things look old, but they're not. Looks Old But Not makes " + |
|||
"awesome vintage goods that are base smart. This ol’ belt just got an upgrade. " |
|||
), |
|||
new Product( |
|||
name: "Sunglasses", |
|||
imageAsset: "products/sunnies", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "fashion", "beauty"}, |
|||
price: 20.00f, |
|||
vendor: _trevor, |
|||
description: |
|||
"Be an optimist. Carry Sunglasses with you at all times. All Tints and " + |
|||
"Shades products come with polarized lenses and base duper UV protection " + |
|||
"so you can look at the sun for however long you want. Sunglasses make you " + |
|||
"look cool, wear them." |
|||
), |
|||
new Product( |
|||
name: "Flatwear", |
|||
imageAsset: "products/flatwear", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"furniture"}, |
|||
price: 30.00f, |
|||
vendor: _trevor, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Salmon Sweater", |
|||
imageAsset: "products/sweater", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion"}, |
|||
price: 300.00f, |
|||
vendor: _stella, |
|||
description: |
|||
"Looks can be deceiving. This sweater comes in a wide variety of " + |
|||
"flavors, including salmon, that pop as soon as they hit your eyes. " + |
|||
"Sweaters heat quickly, so savor the warmth." |
|||
), |
|||
new Product( |
|||
name: "Pine Table", |
|||
imageAsset: "products/table", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"furniture"}, |
|||
price: 63.00f, |
|||
vendor: _stella, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Green Comfort Jacket", |
|||
imageAsset: "products/jacket", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion"}, |
|||
price: 36.00f, |
|||
vendor: _ali, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Chambray Top", |
|||
imageAsset: "products/top", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion"}, |
|||
price: 125.00f, |
|||
vendor: _peter, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Blue Cup", |
|||
imageAsset: "products/cup", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "furniture"}, |
|||
price: 75.00f, |
|||
vendor: _sandra, |
|||
description: |
|||
"Drinksy has been making extraordinary mugs for decades. With each " + |
|||
"cup purchased Drinksy donates a cup to those in need. Buy yourself a mug, " + |
|||
"buy someone else a mug." |
|||
), |
|||
new Product( |
|||
name: "Tea Set", |
|||
imageAsset: "products/teaset", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"furniture", "fashion"}, |
|||
price: 70.00f, |
|||
vendor: _trevor, |
|||
featureTitle: "Beautiful glass teapot", |
|||
featureDescription: |
|||
"Teapot holds extremely hot liquids and pours them from the spout.", |
|||
description: |
|||
"Impress your guests with Tea Set by Kitchen Stuff. Teapot holds extremely " + |
|||
"hot liquids and pours them from the spout. Use the handle, shown on the right, " + |
|||
"so your fingers don’t get burnt while pouring." |
|||
), |
|||
new Product( |
|||
name: "Blue linen napkins", |
|||
imageAsset: "products/napkins", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"furniture", "fashion"}, |
|||
price: 89.00f, |
|||
vendor: _trevor, |
|||
description: |
|||
"Blue linen napkins were meant to go with friends, so you may want to pick " + |
|||
"up a bunch of these. These things are absorbant." |
|||
), |
|||
new Product( |
|||
name: "Dipped Earrings", |
|||
imageAsset: "products/earrings", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion", "beauty"}, |
|||
price: 25.00f, |
|||
vendor: _stella, |
|||
description: |
|||
"WeDipIt does it again. These hand-dipped 4 inch earrings are perfect for " + |
|||
"the office or the beach. Just be sure you don’t drop it in a bucket of " + |
|||
"red paint, then they won’t look dipped anymore." |
|||
), |
|||
new Product( |
|||
name: "Perfect Planters", |
|||
imageAsset: "products/planters", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"latest", "furniture"}, |
|||
price: 30.00f, |
|||
vendor: _ali, |
|||
description: |
|||
"The Perfect Planter Co makes the best vessels for just about anything you " + |
|||
"can pot. This set of Perfect Planters holds succulents and cuttings perfectly. " + |
|||
"Looks great in any room. Keep out of reach from cats." |
|||
), |
|||
new Product( |
|||
name: "Cloud-White Dress", |
|||
imageAsset: "products/dress", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion"}, |
|||
price: 54.00f, |
|||
vendor: _sandra, |
|||
description: |
|||
"Trying to find the perfect outift to match your mood? Try no longer. " + |
|||
"This Cloud-White Dress has you covered for those nights when you need " + |
|||
"to get out, or even if you’re just headed to work." |
|||
), |
|||
new Product( |
|||
name: "Backpack", |
|||
imageAsset: "products/backpack", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "fashion"}, |
|||
price: 25.00f, |
|||
vendor: _peter, |
|||
description: |
|||
"This backpack by Bags ‘n’ stuff can hold just about anything: a laptop, " + |
|||
"a pen, a protractor, notebooks, small animals, plugs for your devices, " + |
|||
"sunglasses, gym clothes, shoes, gloves, two kittens, and even lunch!" |
|||
), |
|||
new Product( |
|||
name: "Charcoal Straw Hat", |
|||
imageAsset: "products/hat", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "fashion", "latest"}, |
|||
price: 25.00f, |
|||
vendor: _ali, |
|||
description: |
|||
"This is the helmet for those warm summer days on the road. " + |
|||
"Jetset approved, these hats have been rigorously tested. Keep that face " + |
|||
"protected from the sun." |
|||
), |
|||
new Product( |
|||
name: "Ginger Scarf", |
|||
imageAsset: "products/scarf", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"latest", "fashion"}, |
|||
price: 17.00f, |
|||
vendor: _peter, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Blush Sweats", |
|||
imageAsset: "products/sweats", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "fashion", "latest"}, |
|||
price: 25.00f, |
|||
vendor: _stella, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Mint Jumper", |
|||
imageAsset: "products/jumper", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"travel", "fashion", "beauty"}, |
|||
price: 25.00f, |
|||
vendor: _peter, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
), |
|||
new Product( |
|||
name: "Ochre Shirt", |
|||
imageAsset: "products/shirt", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
categories: new List<string> {"fashion", "latest"}, |
|||
price: 120.00f, |
|||
vendor: _stella, |
|||
description: |
|||
"Leave the tunnel and the rain is fallin amazing things happen when you wait" |
|||
) |
|||
}; |
|||
|
|||
public static List<Product> allProducts() { |
|||
D.assert(_allProducts.All((Product product) => product.isValid())); |
|||
return new List<Product>(_allProducts); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f29bb63cff3148cbb3ef3be8196d5709 |
|||
timeCreated: 1553240837 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using com.unity.uiwidgets.Runtime.rendering; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using Constants = Unity.UIWidgets.material.Constants; |
|||
using Image = Unity.UIWidgets.widgets.Image; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class ShrineHomeUtils { |
|||
public const float unitSize = Constants.kToolbarHeight; |
|||
|
|||
public static readonly List<Product> _products = new List<Product>(ShrineData.allProducts()); |
|||
public static readonly Dictionary<Product, Order> _shoppingCart = new Dictionary<Product, Order>(); |
|||
|
|||
public const int _childrenPerBlock = 8; |
|||
public const int _rowsPerBlock = 5; |
|||
|
|||
public static int _minIndexInRow(int rowIndex) { |
|||
int blockIndex = rowIndex / _rowsPerBlock; |
|||
return new List<int> {0, 2, 4, 6, 7}[rowIndex % _rowsPerBlock] + blockIndex * _childrenPerBlock; |
|||
} |
|||
|
|||
public static int _maxIndexInRow(int rowIndex) { |
|||
int blockIndex = rowIndex / _rowsPerBlock; |
|||
return new List<int> {1, 3, 5, 6, 7}[rowIndex % _rowsPerBlock] + blockIndex * _childrenPerBlock; |
|||
} |
|||
|
|||
public static int _rowAtIndex(int index) { |
|||
int blockCount = index / _childrenPerBlock; |
|||
return new List<int> {0, 0, 1, 1, 2, 2, 3, 4}[index - blockCount * _childrenPerBlock] + |
|||
blockCount * _rowsPerBlock; |
|||
} |
|||
|
|||
public static int _columnAtIndex(int index) { |
|||
return new List<int> {0, 1, 0, 1, 0, 1, 0, 0}[index % _childrenPerBlock]; |
|||
} |
|||
|
|||
public static int _columnSpanAtIndex(int index) { |
|||
return new List<int> {1, 1, 1, 1, 1, 1, 2, 2}[index % _childrenPerBlock]; |
|||
} |
|||
} |
|||
|
|||
class _ShrineGridLayout : SliverGridLayout { |
|||
public _ShrineGridLayout( |
|||
float? rowStride = null, |
|||
float? columnStride = null, |
|||
float? tileHeight = null, |
|||
float? tileWidth = null |
|||
) { |
|||
this.rowStride = rowStride; |
|||
this.columnStride = columnStride; |
|||
this.tileHeight = tileHeight; |
|||
this.tileWidth = tileWidth; |
|||
} |
|||
|
|||
public readonly float? rowStride; |
|||
public readonly float? columnStride; |
|||
public readonly float? tileHeight; |
|||
public readonly float? tileWidth; |
|||
|
|||
public override int getMinChildIndexForScrollOffset(float scrollOffset) { |
|||
return ShrineHomeUtils._minIndexInRow((int) (scrollOffset / this.rowStride)); |
|||
} |
|||
|
|||
public override int getMaxChildIndexForScrollOffset(float scrollOffset) { |
|||
return ShrineHomeUtils._maxIndexInRow((int) (scrollOffset / this.rowStride)); |
|||
} |
|||
|
|||
public override SliverGridGeometry getGeometryForChildIndex(int index) { |
|||
int row = ShrineHomeUtils._rowAtIndex(index); |
|||
int column = ShrineHomeUtils._columnAtIndex(index); |
|||
int columnSpan = ShrineHomeUtils._columnSpanAtIndex(index); |
|||
return new SliverGridGeometry( |
|||
scrollOffset: row * this.rowStride, |
|||
crossAxisOffset: column * this.columnStride, |
|||
mainAxisExtent: this.tileHeight, |
|||
crossAxisExtent: this.tileWidth + (columnSpan - 1) * this.columnStride |
|||
); |
|||
} |
|||
|
|||
public override float computeMaxScrollOffset(int childCount) { |
|||
if (childCount == 0) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
int rowCount = ShrineHomeUtils._rowAtIndex(childCount - 1) + 1; |
|||
float? rowSpacing = this.rowStride - this.tileHeight; |
|||
return (this.rowStride * rowCount - rowSpacing) ?? 0.0f; |
|||
} |
|||
} |
|||
|
|||
class _ShrineGridDelegate : SliverGridDelegate { |
|||
const float _spacing = 8.0f; |
|||
|
|||
public override SliverGridLayout getLayout(SliverConstraints constraints) { |
|||
float tileWidth = (constraints.crossAxisExtent - _spacing) / 2.0f; |
|||
const float tileHeight = 40.0f + 144.0f + 40.0f; |
|||
return new _ShrineGridLayout( |
|||
tileWidth: tileWidth, |
|||
tileHeight: tileHeight, |
|||
rowStride: tileHeight + _spacing, |
|||
columnStride: tileWidth + _spacing |
|||
); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SliverGridDelegate oldDelegate) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
class _VendorItem : StatelessWidget { |
|||
public _VendorItem(Key key = null, Vendor vendor = null) : base(key: key) { |
|||
D.assert(vendor != null); |
|||
this.vendor = vendor; |
|||
} |
|||
|
|||
public readonly Vendor vendor; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new SizedBox( |
|||
height: 24.0f, |
|||
child: new Row( |
|||
children: new List<Widget> { |
|||
new SizedBox( |
|||
width: 24.0f, |
|||
child: new ClipRRect( |
|||
borderRadius: BorderRadius.circular(12.0f), |
|||
child: Image.asset( |
|||
this.vendor.avatarAsset, |
|||
fit: BoxFit.cover |
|||
) |
|||
) |
|||
), |
|||
new SizedBox(width: 8.0f), |
|||
new Expanded( |
|||
child: new Text(this.vendor.name, style: ShrineTheme.of(context).vendorItemStyle) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
abstract class _PriceItem : StatelessWidget { |
|||
public _PriceItem(Key key = null, Product product = null) |
|||
: base(key: key) { |
|||
D.assert(product != null); |
|||
this.product = product; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
|
|||
public Widget buildItem(BuildContext context, TextStyle style, EdgeInsets padding) { |
|||
BoxDecoration decoration = null; |
|||
if (ShrineHomeUtils._shoppingCart.getOrDefault(this.product) != null) { |
|||
decoration = new BoxDecoration(color: ShrineTheme.of(context).priceHighlightColor); |
|||
} |
|||
|
|||
return new Container( |
|||
padding: padding, |
|||
decoration: decoration, |
|||
child: new Text(this.product.priceString, style: style) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _ProductPriceItem : _PriceItem { |
|||
public _ProductPriceItem(Key key = null, Product product = null) : base(key: key, product: product) { |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return this.buildItem( |
|||
context, |
|||
ShrineTheme.of(context).priceStyle, |
|||
EdgeInsets.symmetric(horizontal: 16.0f, vertical: 8.0f) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _FeaturePriceItem : _PriceItem { |
|||
public _FeaturePriceItem(Key key = null, Product product = null) : base(key: key, product: product) { |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return this.buildItem( |
|||
context, |
|||
ShrineTheme.of(context).featurePriceStyle, |
|||
EdgeInsets.symmetric(horizontal: 24.0f, vertical: 16.0f) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _HeadingLayout : MultiChildLayoutDelegate { |
|||
public _HeadingLayout() { |
|||
} |
|||
|
|||
public const string price = "price"; |
|||
public const string image = "image"; |
|||
public const string title = "title"; |
|||
public const string description = "description"; |
|||
public const string vendor = "vendor"; |
|||
|
|||
public override void performLayout(Size size) { |
|||
Size priceSize = this.layoutChild(price, BoxConstraints.loose(size)); |
|||
this.positionChild(price, new Offset(size.width - priceSize.width, 0.0f)); |
|||
|
|||
float halfWidth = size.width / 2.0f; |
|||
float halfHeight = size.height / 2.0f; |
|||
const float halfUnit = ShrineHomeUtils.unitSize / 2.0f; |
|||
const float margin = 16.0f; |
|||
|
|||
Size imageSize = this.layoutChild(image, BoxConstraints.loose(size)); |
|||
float imageX = imageSize.width < halfWidth - halfUnit |
|||
? halfWidth / 2.0f - imageSize.width / 2.0f - halfUnit |
|||
: halfWidth - imageSize.width; |
|||
this.positionChild(image, new Offset(imageX, halfHeight - imageSize.height / 2.0f)); |
|||
|
|||
float maxTitleWidth = halfWidth + ShrineHomeUtils.unitSize - margin; |
|||
BoxConstraints titleBoxConstraints = new BoxConstraints(maxWidth: maxTitleWidth); |
|||
Size titleSize = this.layoutChild(title, titleBoxConstraints); |
|||
float titleX = halfWidth - ShrineHomeUtils.unitSize; |
|||
float titleY = halfHeight - titleSize.height; |
|||
this.positionChild(title, new Offset(titleX, titleY)); |
|||
|
|||
Size descriptionSize = this.layoutChild(description, titleBoxConstraints); |
|||
float descriptionY = titleY + titleSize.height + margin; |
|||
this.positionChild(description, new Offset(titleX, descriptionY)); |
|||
|
|||
this.layoutChild(vendor, titleBoxConstraints); |
|||
float vendorY = descriptionY + descriptionSize.height + margin; |
|||
this.positionChild(vendor, new Offset(titleX, vendorY)); |
|||
} |
|||
|
|||
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
class _HeadingShrineHome : StatelessWidget { |
|||
public _HeadingShrineHome(Key key = null, Product product = null) : base(key: key) { |
|||
D.assert(product != null); |
|||
D.assert(product.featureTitle != null); |
|||
D.assert(product.featureDescription != null); |
|||
this.product = product; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Size screenSize = MediaQuery.of(context).size; |
|||
ShrineTheme theme = ShrineTheme.of(context); |
|||
return new SizedBox( |
|||
height: screenSize.width > screenSize.height |
|||
? (screenSize.height - Constants.kToolbarHeight) * 0.85f |
|||
: (screenSize.height - Constants.kToolbarHeight) * 0.70f, |
|||
child: new Container( |
|||
decoration: new BoxDecoration( |
|||
color: theme.cardBackgroundColor, |
|||
border: new Border(bottom: new BorderSide(color: theme.dividerColor)) |
|||
), |
|||
child: new CustomMultiChildLayout( |
|||
layoutDelegate: new _HeadingLayout(), |
|||
children: new List<Widget> { |
|||
new LayoutId( |
|||
id: _HeadingLayout.price, |
|||
child: new _FeaturePriceItem(product: this.product) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayout.image, |
|||
child: Image.asset( |
|||
this.product.imageAsset, |
|||
fit: BoxFit.cover |
|||
) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayout.title, |
|||
child: new Text(this.product.featureTitle, style: theme.featureTitleStyle) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayout.description, |
|||
child: new Text(this.product.featureDescription, style: theme.featureStyle) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayout.vendor, |
|||
child: new _VendorItem(vendor: this.product.vendor) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _ProductItem : StatelessWidget { |
|||
public _ProductItem(Key key = null, Product product = null, VoidCallback onPressed = null) : base(key: key) { |
|||
D.assert(product != null); |
|||
this.product = product; |
|||
this.onPressed = onPressed; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
public readonly VoidCallback onPressed; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new Card( |
|||
child: new Stack( |
|||
children: new List<Widget> { |
|||
new Column( |
|||
children: new List<Widget> { |
|||
new Align( |
|||
alignment: Alignment.centerRight, |
|||
child: new _ProductPriceItem(product: this.product) |
|||
), |
|||
new Container( |
|||
width: 144.0f, |
|||
height: 144.0f, |
|||
padding: EdgeInsets.symmetric(horizontal: 8.0f), |
|||
child:new Hero( |
|||
tag: this.product.tag, |
|||
child: Image.asset(this.product.imageAsset, |
|||
fit: BoxFit.contain |
|||
) |
|||
) |
|||
), |
|||
new Padding( |
|||
padding: EdgeInsets.symmetric(horizontal: 8.0f), |
|||
child: new _VendorItem(vendor: this.product.vendor) |
|||
) |
|||
} |
|||
), |
|||
new Material( |
|||
type: MaterialType.transparency, |
|||
child: new InkWell(onTap: this.onPressed == null |
|||
? (GestureTapCallback) null |
|||
: () => { this.onPressed(); }) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class ShrineHome : StatefulWidget { |
|||
public override State createState() { |
|||
return new _ShrineHomeState(); |
|||
} |
|||
} |
|||
|
|||
class _ShrineHomeState : State<ShrineHome> { |
|||
public _ShrineHomeState() { |
|||
} |
|||
|
|||
readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key(debugLabel: "Shrine Home"); |
|||
static readonly _ShrineGridDelegate gridDelegate = new _ShrineGridDelegate(); |
|||
|
|||
void _showOrderPage(Product product) { |
|||
Order order = ShrineHomeUtils._shoppingCart.getOrDefault(product) ?? new Order(product: product); |
|||
Navigator.push(this.context, new ShrineOrderRoute( |
|||
order: order, |
|||
builder: (BuildContext context) => { |
|||
return new OrderPage( |
|||
order: order, |
|||
products: ShrineHomeUtils._products, |
|||
shoppingCart: ShrineHomeUtils._shoppingCart |
|||
); |
|||
} |
|||
)).Then(completedOrder => { |
|||
D.assert((completedOrder as Order).product != null); |
|||
if ((completedOrder as Order).quantity == 0) { |
|||
ShrineHomeUtils._shoppingCart.Remove((completedOrder as Order).product); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Product featured = ShrineHomeUtils._products.First((Product product) => product.featureDescription != null); |
|||
return new ShrinePage( |
|||
scaffoldKey: this._scaffoldKey, |
|||
products: ShrineHomeUtils._products, |
|||
shoppingCart: ShrineHomeUtils._shoppingCart, |
|||
body: new CustomScrollView( |
|||
slivers: new List<Widget> { |
|||
new SliverToBoxAdapter(child: new _HeadingShrineHome(product: featured)), |
|||
new SliverSafeArea( |
|||
top: false, |
|||
minimum: EdgeInsets.all(16.0f), |
|||
sliver: new SliverGrid( |
|||
gridDelegate: gridDelegate, |
|||
layoutDelegate: new SliverChildListDelegate( |
|||
ShrineHomeUtils._products.Select<Product, Widget>((Product product) => { |
|||
return new _ProductItem( |
|||
product: product, |
|||
onPressed: () => { this._showOrderPage(product); } |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ec9f3366e13014909b0287e1305641e1 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using com.unity.uiwidgets.Runtime.rendering; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using Image = Unity.UIWidgets.widgets.Image; |
|||
using Material = Unity.UIWidgets.material.Material; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class _ProductItemShrineOrder : StatelessWidget { |
|||
public _ProductItemShrineOrder( |
|||
Key key = null, |
|||
Product product = null, |
|||
int? quantity = null, |
|||
ValueChanged<int> onChanged = null |
|||
) : base(key: key) { |
|||
D.assert(product != null); |
|||
D.assert(quantity != null); |
|||
D.assert(onChanged != null); |
|||
this.product = product; |
|||
this.quantity = quantity; |
|||
this.onChanged = onChanged; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
public readonly int? quantity; |
|||
public readonly ValueChanged<int> onChanged; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
ShrineTheme theme = ShrineTheme.of(context); |
|||
return new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: new List<Widget>{ |
|||
new Text(this.product.name, style: theme.featureTitleStyle), |
|||
new SizedBox(height: 24.0f), |
|||
new Text(this.product.description, style: theme.featureStyle), |
|||
new SizedBox(height: 16.0f), |
|||
new Padding( |
|||
padding: EdgeInsets.only(top: 8.0f, bottom: 8.0f, right: 88.0f), |
|||
child: new DropdownButtonHideUnderline( |
|||
child: new Container( |
|||
decoration: new BoxDecoration( |
|||
border: Border.all( |
|||
color: new Color(0xFFD9D9D9) |
|||
) |
|||
), |
|||
child: new DropdownButton<string>( |
|||
items: new List<int>{0, 1, 2, 3, 4, 5}.Select<int, DropdownMenuItem<string>>((int value) => { |
|||
return new DropdownMenuItem<string>( |
|||
value: $"{value}", |
|||
child: new Padding( |
|||
padding: EdgeInsets.only(left: 8.0f), |
|||
child: new Text($"Quantity {value}", style: theme.quantityMenuStyle) |
|||
) |
|||
); |
|||
}).ToList(), |
|||
value: $"{this.quantity}", |
|||
onChanged: (value) => { |
|||
this.onChanged(int.Parse(value)); |
|||
}) |
|||
) |
|||
) |
|||
) |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _VendorItemShrineOrder : StatelessWidget { |
|||
public _VendorItemShrineOrder( Key key = null, Vendor vendor = null ) |
|||
: base(key: key) { |
|||
D.assert(vendor != null); |
|||
this.vendor = vendor; |
|||
} |
|||
|
|||
public readonly Vendor vendor; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
ShrineTheme theme = ShrineTheme.of(context); |
|||
return new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: new List<Widget>{ |
|||
new SizedBox( |
|||
height: 24.0f, |
|||
child: new Align( |
|||
alignment: Alignment.bottomLeft, |
|||
child: new Text(this.vendor.name, style: theme.vendorTitleStyle) |
|||
) |
|||
), |
|||
new SizedBox(height: 16.0f), |
|||
new Text(this.vendor.description, style: theme.vendorStyle) |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _HeadingLayoutShrineOrder : MultiChildLayoutDelegate { |
|||
public _HeadingLayoutShrineOrder() {} |
|||
|
|||
public const string image = "image"; |
|||
public const string icon = "icon"; |
|||
public const string product = "product"; |
|||
public const string vendor = "vendor"; |
|||
|
|||
public override void performLayout(Size size) { |
|||
const float margin = 56.0f; |
|||
bool landscape = size.width > size.height; |
|||
float imageWidth = (landscape ? size.width / 2.0f : size.width) - margin * 2.0f; |
|||
BoxConstraints imageConstraints = new BoxConstraints(maxHeight: 224.0f, maxWidth: imageWidth); |
|||
Size imageSize = this.layoutChild(image, imageConstraints); |
|||
const float imageY = 0.0f; |
|||
this.positionChild(image, new Offset(margin, imageY)); |
|||
|
|||
float productWidth = landscape ? size.width / 2.0f : size.width - margin; |
|||
BoxConstraints productConstraints = new BoxConstraints(maxWidth: productWidth); |
|||
Size productSize = this.layoutChild(product, productConstraints); |
|||
float productX = landscape ? size.width / 2.0f : margin; |
|||
float productY = landscape ? 0.0f : imageY + imageSize.height + 16.0f; |
|||
this.positionChild(product, new Offset(productX, productY)); |
|||
|
|||
Size iconSize = this.layoutChild(icon, BoxConstraints.loose(size)); |
|||
this.positionChild(icon, new Offset(productX - iconSize.width - 16.0f, productY + 8.0f)); |
|||
|
|||
float vendorWidth = landscape ? size.width - margin : productWidth; |
|||
this.layoutChild(vendor, new BoxConstraints(maxWidth: vendorWidth)); |
|||
float vendorX = landscape ? margin : productX; |
|||
float vendorY = productY + productSize.height + 16.0f; |
|||
this.positionChild(vendor, new Offset(vendorX, vendorY)); |
|||
} |
|||
|
|||
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => true; |
|||
} |
|||
|
|||
class _HeadingShrineOrder : StatelessWidget { |
|||
public _HeadingShrineOrder( |
|||
Key key = null, |
|||
Product product = null, |
|||
int? quantity = null, |
|||
ValueChanged<int> quantityChanged = null |
|||
) : base(key: key) { |
|||
D.assert(product != null); |
|||
D.assert(quantity != null && quantity >= 0 && quantity <= 5); |
|||
this.product = product; |
|||
this.quantity = quantity; |
|||
this.quantityChanged = quantityChanged; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
public readonly int? quantity; |
|||
public readonly ValueChanged<int> quantityChanged; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Size screenSize = MediaQuery.of(context).size; |
|||
return new SizedBox( |
|||
height: (screenSize.height - Constants.kToolbarHeight) * 1.35f, |
|||
child: new Material( |
|||
type: MaterialType.card, |
|||
elevation: 0.0f, |
|||
child: new Padding( |
|||
padding: EdgeInsets.only(left: 16.0f, top: 18.0f, right: 16.0f, bottom: 24.0f), |
|||
child: new CustomMultiChildLayout( |
|||
layoutDelegate: new _HeadingLayoutShrineOrder(), |
|||
children: new List<Widget>{ |
|||
new LayoutId( |
|||
id: _HeadingLayoutShrineOrder.image, |
|||
child: new Hero( |
|||
tag: this.product.tag, |
|||
child: Image.asset(this.product.imageAsset, |
|||
fit: BoxFit.contain, |
|||
alignment: Alignment.center |
|||
) |
|||
) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayoutShrineOrder.icon, |
|||
child: new Icon( |
|||
Icons.info_outline, |
|||
size: 24.0f, |
|||
color: new Color(0xFFFFE0E0) |
|||
) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayoutShrineOrder.product, |
|||
child: new _ProductItemShrineOrder( |
|||
product: this.product, |
|||
quantity: this.quantity, |
|||
onChanged: this.quantityChanged |
|||
) |
|||
), |
|||
new LayoutId( |
|||
id: _HeadingLayoutShrineOrder.vendor, |
|||
child: new _VendorItemShrineOrder(vendor: this.product.vendor) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class OrderPage : StatefulWidget { |
|||
public OrderPage( |
|||
Key key = null, |
|||
Order order = null, |
|||
List<Product> products = null, |
|||
Dictionary<Product, Order> shoppingCart = null |
|||
) : base(key: key) { |
|||
D.assert(order != null); |
|||
D.assert(products != null && products.isNotEmpty()); |
|||
D.assert(shoppingCart != null); |
|||
this.order = order; |
|||
this.products = products; |
|||
this.shoppingCart = shoppingCart; |
|||
} |
|||
|
|||
public readonly Order order; |
|||
public readonly List<Product> products; |
|||
public readonly Dictionary<Product, Order> shoppingCart; |
|||
|
|||
public override State createState() => new _OrderPageState(); |
|||
} |
|||
|
|||
class _OrderPageState : State<OrderPage> { |
|||
GlobalKey<ScaffoldState> scaffoldKey; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this.scaffoldKey = GlobalKey<ScaffoldState>.key(debugLabel: $"Shrine Order {this.widget.order}"); |
|||
} |
|||
|
|||
public Order currentOrder { |
|||
get { return ShrineOrderRoute.of(this.context).order; } |
|||
set { |
|||
ShrineOrderRoute.of(this.context).order = value; |
|||
} |
|||
} |
|||
|
|||
void updateOrder( int? quantity = null, bool? inCart = null) { |
|||
Order newOrder = this.currentOrder.copyWith(quantity: quantity, inCart: inCart); |
|||
if (this.currentOrder != newOrder) { |
|||
this.setState(() => { |
|||
this.widget.shoppingCart[newOrder.product] = newOrder; |
|||
this.currentOrder = newOrder; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
void showSnackBarMessage(string message) { |
|||
this.scaffoldKey.currentState.showSnackBar(new SnackBar(content: new Text(message))); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new ShrinePage( |
|||
scaffoldKey: this.scaffoldKey, |
|||
products: this.widget.products, |
|||
shoppingCart: this.widget.shoppingCart, |
|||
floatingActionButton: new FloatingActionButton( |
|||
onPressed: () => { |
|||
this.updateOrder(inCart: true); |
|||
int n = this.currentOrder.quantity; |
|||
string item = this.currentOrder.product.name; |
|||
string message = n == 1 ? $"is one {item} item" : $"are {n} {item} items"; |
|||
this.showSnackBarMessage( |
|||
$"There {message} in the shopping cart." |
|||
); |
|||
}, |
|||
backgroundColor: new Color(0xFF16F0F0), |
|||
tooltip: "Add to cart", |
|||
child: new Icon( |
|||
Icons.add_shopping_cart, |
|||
color: Colors.black |
|||
) |
|||
), |
|||
body: new CustomScrollView( |
|||
slivers: new List<Widget>{ |
|||
new SliverToBoxAdapter( |
|||
child: new _HeadingShrineOrder( |
|||
product: this.widget.order.product, |
|||
quantity: this.currentOrder.quantity, |
|||
quantityChanged: (int value) => { this.updateOrder(quantity: value); } |
|||
) |
|||
), |
|||
new SliverSafeArea( |
|||
top: false, |
|||
minimum: EdgeInsets.fromLTRB(8.0f, 32.0f, 8.0f, 8.0f), |
|||
sliver: new SliverGrid( |
|||
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent( |
|||
maxCrossAxisExtent: 248.0f, |
|||
mainAxisSpacing: 8.0f, |
|||
crossAxisSpacing: 8.0f |
|||
), |
|||
layoutDelegate: new SliverChildListDelegate( |
|||
this.widget.products |
|||
.FindAll((Product product) => product != this.widget.order.product) |
|||
.Select<Product, Widget>((Product product) => { |
|||
return new Card( |
|||
elevation: 1.0f, |
|||
child: Image.asset( |
|||
product.imageAsset, |
|||
fit: BoxFit.contain |
|||
) |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class ShrineOrderRoute : ShrinePageRoute<Order> { |
|||
public ShrineOrderRoute( |
|||
Order order = null, |
|||
WidgetBuilder builder = null, |
|||
RouteSettings settings = null |
|||
) : base(builder: builder, settings: settings) { |
|||
D.assert(order != null); |
|||
this.order = order; |
|||
} |
|||
|
|||
public Order order; |
|||
|
|||
public new Order currentResult { |
|||
get { |
|||
return this.order; |
|||
} |
|||
} |
|||
|
|||
public new static ShrineOrderRoute of(BuildContext context) => (ShrineOrderRoute) ModalRoute.of(context); |
|||
} |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b0720924e140457dbc8626755c82f3ba |
|||
timeCreated: 1553244438 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
public enum ShrineAction { |
|||
sortByPrice, |
|||
sortByProduct, |
|||
emptyCart |
|||
} |
|||
|
|||
public class ShrinePage : StatefulWidget { |
|||
public ShrinePage( |
|||
Key key = null, |
|||
GlobalKey<ScaffoldState> scaffoldKey = null, |
|||
Widget body = null, |
|||
Widget floatingActionButton = null, |
|||
List<Product> products = null, |
|||
Dictionary<Product, Order> shoppingCart = null |
|||
) : base(key: key) { |
|||
D.assert(body != null); |
|||
D.assert(scaffoldKey != null); |
|||
this.scaffoldKey = scaffoldKey; |
|||
this.body = body; |
|||
this.floatingActionButton = floatingActionButton; |
|||
this.products = products; |
|||
this.shoppingCart = shoppingCart; |
|||
} |
|||
|
|||
public readonly GlobalKey<ScaffoldState> scaffoldKey; |
|||
public readonly Widget body; |
|||
public readonly Widget floatingActionButton; |
|||
public readonly List<Product> products; |
|||
public readonly Dictionary<Product, Order> shoppingCart; |
|||
|
|||
public override State createState() { |
|||
return new ShrinePageState(); |
|||
} |
|||
} |
|||
|
|||
public class ShrinePageState : State<ShrinePage> { |
|||
float _appBarElevation = 0.0f; |
|||
|
|||
bool _handleScrollNotification(ScrollNotification notification) { |
|||
float elevation = notification.metrics.extentBefore() <= 0.0f ? 0.0f : 1.0f; |
|||
if (elevation != this._appBarElevation) { |
|||
this.setState(() => { this._appBarElevation = elevation; }); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void _showShoppingCart() { |
|||
BottomSheetUtils.showModalBottomSheet<object>(context: this.context, builder: (BuildContext context) => { |
|||
if (this.widget.shoppingCart.isEmpty()) { |
|||
return new Padding( |
|||
padding: EdgeInsets.all(24.0f), |
|||
child: new Text("The shopping cart is empty") |
|||
); |
|||
} |
|||
|
|||
return new ListView( |
|||
padding: Constants.kMaterialListPadding, |
|||
children: this.widget.shoppingCart.Values.Select<Order, Widget>((Order order) => { |
|||
return new ListTile( |
|||
title: new Text(order.product.name), |
|||
leading: new Text($"{order.quantity}"), |
|||
subtitle: new Text(order.product.vendor.name) |
|||
); |
|||
}).ToList() |
|||
); |
|||
}); |
|||
} |
|||
|
|||
void _sortByPrice() { |
|||
this.widget.products.Sort((Product a, Product b) => a.price?.CompareTo(b.price) ?? (b == null ? 0 : -1)); |
|||
} |
|||
|
|||
void _sortByProduct() { |
|||
this.widget.products.Sort((Product a, Product b) => a.name.CompareTo(b.name)); |
|||
} |
|||
|
|||
void _emptyCart() { |
|||
this.widget.shoppingCart.Clear(); |
|||
this.widget.scaffoldKey.currentState.showSnackBar( |
|||
new SnackBar(content: new Text("Shopping cart is empty"))); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
ShrineTheme theme = ShrineTheme.of(context); |
|||
return new Scaffold( |
|||
key: this.widget.scaffoldKey, |
|||
appBar: new AppBar( |
|||
elevation: this._appBarElevation, |
|||
backgroundColor: theme.appBarBackgroundColor, |
|||
iconTheme: Theme.of(context).iconTheme, |
|||
brightness: Brightness.light, |
|||
flexibleSpace: new Container( |
|||
decoration: new BoxDecoration( |
|||
border: new Border( |
|||
bottom: new BorderSide(color: theme.dividerColor) |
|||
) |
|||
) |
|||
), |
|||
title: new Text("SHRINE", style: ShrineTheme.of(context).appBarTitleStyle), |
|||
centerTitle: true, |
|||
actions: new List<Widget> { |
|||
new IconButton( |
|||
icon: new Icon(Icons.shopping_cart), |
|||
tooltip: "Shopping cart", |
|||
onPressed: this._showShoppingCart |
|||
), |
|||
new PopupMenuButton<ShrineAction>( |
|||
itemBuilder: (BuildContext _) => new List<PopupMenuEntry<ShrineAction>> { |
|||
new PopupMenuItem<ShrineAction>( |
|||
value: ShrineAction.sortByPrice, |
|||
child: new Text("Sort by price") |
|||
), |
|||
new PopupMenuItem<ShrineAction>( |
|||
value: ShrineAction.sortByProduct, |
|||
child: new Text("Sort by product") |
|||
), |
|||
new PopupMenuItem<ShrineAction>( |
|||
value: ShrineAction.emptyCart, |
|||
child: new Text("Empty shopping cart") |
|||
) |
|||
}, |
|||
onSelected: (ShrineAction action) => { |
|||
switch (action) { |
|||
case ShrineAction.sortByPrice: |
|||
this.setState(this._sortByPrice); |
|||
break; |
|||
case ShrineAction.sortByProduct: |
|||
this.setState(this._sortByProduct); |
|||
break; |
|||
case ShrineAction.emptyCart: |
|||
this.setState(this._emptyCart); |
|||
break; |
|||
} |
|||
} |
|||
) |
|||
} |
|||
), |
|||
floatingActionButton: this.widget.floatingActionButton, |
|||
body: new NotificationListener<ScrollNotification>( |
|||
onNotification: this._handleScrollNotification, |
|||
child: this.widget.body |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 81f9ca5ad3e848f4889059abd3037d17 |
|||
timeCreated: 1553246179 |
|
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
public class ShrineStyle : TextStyle { |
|||
public ShrineStyle(bool inherit, Color color, float fontSize, FontWeight fontWeight, TextBaseline textBaseline, |
|||
string fontFamily = null |
|||
) : base(inherit: inherit, color: color, fontSize: fontSize, fontWeight: fontWeight, fontFamily: fontFamily, |
|||
textBaseline: textBaseline) { |
|||
} |
|||
|
|||
public static ShrineStyle roboto(float size, FontWeight weight, Color color) { |
|||
return new ShrineStyle(inherit: false, color: color, fontSize: size, fontWeight: weight, |
|||
textBaseline: TextBaseline.alphabetic); |
|||
} |
|||
|
|||
public static ShrineStyle abrilFatface(float size, FontWeight weight, Color color) { |
|||
return new ShrineStyle(inherit: false, color: color, fontFamily: "AbrilFatface", fontSize: size, |
|||
fontWeight: weight, textBaseline: TextBaseline.alphabetic); |
|||
} |
|||
} |
|||
|
|||
public class ShrineThemeUtils { |
|||
public static TextStyle robotoRegular12(Color color) { |
|||
return ShrineStyle.roboto(12.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle robotoLight12(Color color) { |
|||
return ShrineStyle.roboto(12.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle robotoRegular14(Color color) { |
|||
return ShrineStyle.roboto(14.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle robotoMedium14(Color color) { |
|||
return ShrineStyle.roboto(14.0f, FontWeight.w700, color); |
|||
} |
|||
|
|||
public static TextStyle robotoLight14(Color color) { |
|||
return ShrineStyle.roboto(14.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle robotoRegular16(Color color) { |
|||
return ShrineStyle.roboto(16.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle robotoRegular20(Color color) { |
|||
return ShrineStyle.roboto(20.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle abrilFatfaceRegular24(Color color) { |
|||
return ShrineStyle.abrilFatface(24.0f, FontWeight.w400, color); |
|||
} |
|||
|
|||
public static TextStyle abrilFatfaceRegular34(Color color) { |
|||
return ShrineStyle.abrilFatface(34.0f, FontWeight.w400, color); |
|||
} |
|||
} |
|||
|
|||
public class ShrineTheme : InheritedWidget { |
|||
public ShrineTheme(Key key = null, Widget child = null) |
|||
: base(key: key, child: child) { |
|||
D.assert(child != null); |
|||
} |
|||
|
|||
public readonly Color cardBackgroundColor = Colors.white; |
|||
public readonly Color appBarBackgroundColor = Colors.white; |
|||
public readonly Color dividerColor = new Color(0xFFD9D9D9); |
|||
public readonly Color priceHighlightColor = new Color(0xFFFFE0E0); |
|||
|
|||
public readonly TextStyle appBarTitleStyle = ShrineThemeUtils.robotoRegular20(Colors.black87); |
|||
public readonly TextStyle vendorItemStyle = ShrineThemeUtils.robotoRegular12(new Color(0xFF81959D)); |
|||
public readonly TextStyle priceStyle = ShrineThemeUtils.robotoRegular14(Colors.black87); |
|||
|
|||
public readonly TextStyle featureTitleStyle = |
|||
ShrineThemeUtils.abrilFatfaceRegular34(new Color(0xFF0A3142)); |
|||
|
|||
public readonly TextStyle featurePriceStyle = ShrineThemeUtils.robotoRegular16(Colors.black87); |
|||
public readonly TextStyle featureStyle = ShrineThemeUtils.robotoLight14(Colors.black54); |
|||
public readonly TextStyle orderTitleStyle = ShrineThemeUtils.abrilFatfaceRegular24(Colors.black87); |
|||
public readonly TextStyle orderStyle = ShrineThemeUtils.robotoLight14(Colors.black54); |
|||
public readonly TextStyle vendorTitleStyle = ShrineThemeUtils.robotoMedium14(Colors.black87); |
|||
public readonly TextStyle vendorStyle = ShrineThemeUtils.robotoLight14(Colors.black54); |
|||
public readonly TextStyle quantityMenuStyle = ShrineThemeUtils.robotoLight14(Colors.black54); |
|||
|
|||
public static ShrineTheme of(BuildContext context) { |
|||
return (ShrineTheme) context.inheritFromWidgetOfExactType(typeof(ShrineTheme)); |
|||
} |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 468619e1fd4f4437ba3f0929e269aab4 |
|||
timeCreated: 1553241961 |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
public class Vendor { |
|||
public Vendor( |
|||
string name, |
|||
string description, |
|||
string avatarAsset, |
|||
string avatarAssetPackage |
|||
) { |
|||
this.name = name; |
|||
this.description = description; |
|||
this.avatarAsset = avatarAsset; |
|||
this.avatarAssetPackage = avatarAssetPackage; |
|||
} |
|||
|
|||
public readonly string name; |
|||
public readonly string description; |
|||
public readonly string avatarAsset; |
|||
public readonly string avatarAssetPackage; |
|||
|
|||
public bool isValid() { |
|||
return this.name != null && this.description != null && this.avatarAsset != null; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "Vendor($name)"; |
|||
} |
|||
} |
|||
|
|||
public class Product { |
|||
public Product( |
|||
string name = null, |
|||
string description = null, |
|||
string featureTitle = null, |
|||
string featureDescription = null, |
|||
string imageAsset = null, |
|||
string imageAssetPackage = null, |
|||
List<string> categories = null, |
|||
float? price = null, |
|||
Vendor vendor = null |
|||
) { |
|||
this.name = name; |
|||
this.description = description; |
|||
this.featureTitle = featureTitle; |
|||
this.featureDescription = featureDescription; |
|||
this.imageAsset = imageAsset; |
|||
this.imageAssetPackage = imageAssetPackage; |
|||
this.categories = categories; |
|||
this.price = price; |
|||
this.vendor = vendor; |
|||
} |
|||
|
|||
public readonly string name; |
|||
public readonly string description; |
|||
public readonly string featureTitle; |
|||
public readonly string featureDescription; |
|||
public readonly string imageAsset; |
|||
public readonly string imageAssetPackage; |
|||
public readonly List<string> categories; |
|||
public readonly float? price; |
|||
public readonly Vendor vendor; |
|||
|
|||
public string tag { |
|||
get { return this.name; } |
|||
} |
|||
|
|||
public string priceString { |
|||
get { return $"${(this.price ?? 0.0f).floor()}"; } |
|||
} |
|||
|
|||
public bool isValid() { |
|||
return this.name != null && this.description != null && this.imageAsset != null && |
|||
this.categories != null && this.categories.isNotEmpty() && this.price != null && |
|||
this.vendor.isValid(); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return $"Product({this.name})"; |
|||
} |
|||
} |
|||
|
|||
public class Order { |
|||
public Order(Product product, int quantity = 1, bool inCart = false) { |
|||
D.assert(product != null); |
|||
D.assert(quantity >= 0); |
|||
this.product = product; |
|||
this.quantity = quantity; |
|||
this.inCart = inCart; |
|||
} |
|||
|
|||
public readonly Product product; |
|||
public readonly int quantity; |
|||
public readonly bool inCart; |
|||
|
|||
public Order copyWith(Product product = null, int? quantity = null, bool? inCart = null) { |
|||
return new Order( |
|||
product: product ?? this.product, |
|||
quantity: quantity ?? this.quantity, |
|||
inCart: inCart ?? this.inCart |
|||
); |
|||
} |
|||
|
|||
public static bool operator ==(Order left, Order right) { |
|||
if (left is null && right is null) return true; |
|||
if (left is null || right is null) return false; |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
public static bool operator !=(Order left, Order right) { |
|||
if (left is null && right is null) return false; |
|||
if (left is null || right is null) return true; |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
public bool Equals(Order other) { |
|||
return this.product == other.product && |
|||
this.quantity == other.quantity && |
|||
this.inCart == other.inCart; |
|||
} |
|||
|
|||
public override bool Equals(object obj) { |
|||
if (ReferenceEquals(null, obj)) { |
|||
return false; |
|||
} |
|||
|
|||
if (ReferenceEquals(this, obj)) { |
|||
return true; |
|||
} |
|||
|
|||
if (obj.GetType() != this.GetType()) { |
|||
return false; |
|||
} |
|||
|
|||
return this.Equals((Order) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = (this.product != null ? this.product.GetHashCode() : 0); |
|||
hashCode = (hashCode * 397) ^ this.quantity.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.inCart.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return $"Order({this.product}, quantity={this.quantity}, inCart={this.inCart})"; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 924c1662fb504687af28a4f05901a20a |
|||
timeCreated: 1553240139 |
1001
Tests/Resources/people/ali_landscape.png
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: 0842a5ed1d4784702990d69f6c5d348d |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 321c11a98ef1c452ba9bf4fad8ac67fe |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: f644f877472c942209cc4ff5beaf452a |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 739817fca86d74ffda90f9a891db4c99 |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 61c32ad851b0c4c90a05f5857c8bf810 |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 89e334df4c00c47258db57d508fcb3d0 |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 88e5367b95d2f462693ad5524593ab14 |
|||
TextureImporter: |
|||
fileIDToRecycleName: {} |
|||
externalObjects: {} |
|||
serializedVersion: 9 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: -1 |
|||
mipBias: -100 |
|||
wrapU: -1 |
|||
wrapV: -1 |
|||
wrapW: -1 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
platformSettings: |
|||
- serializedVersion: 2 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 2048 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue