浏览代码

Merge remote-tracking branch 'upstream/master'

/main
fzhangtj 6 年前
当前提交
96329329
共有 52 个文件被更改,包括 7197 次插入68 次删除
  1. 6
      .DS_Store
  2. 26
      Runtime/editor/editor_utils.cs
  3. 11
      Runtime/editor/editor_window.cs
  4. 93
      Runtime/engine/DisplayMetrics.cs
  5. 32
      Runtime/engine/UIWidgetsPanel.cs
  6. 1
      Runtime/material/checkbox.cs
  7. 2
      Runtime/widgets/safe_area.cs
  8. 81
      Runtime/widgets/sliver.cs
  9. 70
      Runtime/widgets/sliver_persistent_header.cs
  10. 4
      Samples/UIWidgetsGallery/gallery/demo.cs
  11. 18
      Samples/UIWidgetsGallery/gallery/demos.cs
  12. 34
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h
  13. 26
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h.meta
  14. 108
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm
  15. 36
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm.meta
  16. 451
      Runtime/rendering/sliver_grid.cs
  17. 11
      Runtime/rendering/sliver_grid.cs.meta
  18. 553
      Runtime/widgets/heroes.cs
  19. 3
      Runtime/widgets/heroes.cs.meta
  20. 8
      Samples/UIWidgetsGallery/demo/shrine.meta
  21. 40
      Samples/UIWidgetsGallery/demo/shrine_demo.cs
  22. 3
      Samples/UIWidgetsGallery/demo/shrine_demo.cs.meta
  23. 8
      Tests/Resources/people.meta
  24. 280
      Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs
  25. 3
      Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs.meta
  26. 410
      Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs
  27. 11
      Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs.meta
  28. 3
      Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs.meta
  29. 156
      Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs
  30. 3
      Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs.meta
  31. 98
      Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs
  32. 3
      Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs.meta
  33. 153
      Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs
  34. 3
      Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs.meta
  35. 341
      Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs
  36. 1001
      Tests/Resources/people/ali_landscape.png
  37. 88
      Tests/Resources/people/ali_landscape.png.meta
  38. 8
      Tests/Resources/people/square.meta
  39. 457
      Tests/Resources/people/square/ali.png
  40. 88
      Tests/Resources/people/square/ali.png.meta
  41. 509
      Tests/Resources/people/square/peter.png
  42. 88
      Tests/Resources/people/square/peter.png.meta
  43. 698
      Tests/Resources/people/square/sandra.png
  44. 88
      Tests/Resources/people/square/sandra.png.meta
  45. 393
      Tests/Resources/people/square/stella.png
  46. 88
      Tests/Resources/people/square/stella.png.meta
  47. 574
      Tests/Resources/people/square/trevor.png
  48. 88
      Tests/Resources/people/square/trevor.png.meta
  49. 8
      scripts/node_modules.meta

6
.DS_Store


Bud1  d.batIl  @� @� @� @ build.batIlocblob;(������build.bat.metaIlocblob�(������build.shIlocblob(������ build.sh.metaIlocblob�(������ CHANGELOG.mdIlocblob�(������CHANGELOG.md.metaIlocblob;�������CONTRIBUTING.mdIlocblob��������CONTRIBUTING.md.metaIlocblob�������Documentation~Ilocblob��������EditorIlocblob�������� Editor.metaIlocblob;������
Bud1 GELOG.  @� @� @� @ CHANGELOG.mdIlocblob�(������CHANGELOG.md.metaIlocblob;�������CONTRIBUTING.mdIlocblob��������CONTRIBUTING.md.metaIlocblob�������Documentation~Ilocblob��������EditorIlocblob�������� Editor.metaIlocblob;������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;������� E DSDB `� @� @� @lesIlocblob�������� Samples.metaIlocblob�������scriptsIlocblob�������� scripts.metaIlocblob��������TestsIlocblob;X������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;�������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;������� E DSDB `� @� @� @;X������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;�������

26
Runtime/editor/editor_utils.cs


using System.Collections;
using System.Reflection;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.ui;
using UnityEngine;

public float devicePixelRatio {
get { return this._lastDevicePixelRatio; }
}
public viewMetrics viewMetrics {
get {
return new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
}
}
public WindowPadding viewPadding {
get { return WindowPadding.zero; }
}
public WindowPadding viewInsets {
get { return WindowPadding.zero; }
}
}
static class GameViewUtil {

11
Runtime/editor/editor_window.cs


float _lastWindowWidth;
float _lastWindowHeight;
bool _viewMetricsChanged;
readonly MicrotaskQueue _microtaskQueue = new MicrotaskQueue();
readonly TimerProvider _timerProvider = new TimerProvider();
readonly Rasterizer _rasterizer = new Rasterizer();

}
protected virtual void updateSafeArea() {
}
public void onViewMetricsChanged() {
this._viewMetricsChanged = true;
}
protected abstract bool hasFocus();

return true;
}
if (this._viewMetricsChanged) {
return true;
}
return false;
}

this._lastWindowHeight * this._devicePixelRatio);
this.updateSafeArea();
this._viewMetricsChanged = false;
if (this.onMetricsChanged != null) {
this.onMetricsChanged();
}

93
Runtime/engine/DisplayMetrics.cs


using System;
using System.Runtime.InteropServices;
using Unity.UIWidgets.ui;
[StructLayout(LayoutKind.Sequential)]
public struct viewMetrics {
public float insets_top;
public float insets_bottom;
public float insets_left;
public float insets_right;
public float padding_top;
public float padding_bottom;
public float padding_left;
public float padding_right;
}
public static class DisplayMetricsProvider {
public static Func<DisplayMetrics> provider = () => new PlayerDisplayMetrics();
}

void Update();
float devicePixelRatio { get; }
viewMetrics viewMetrics { get; }
WindowPadding viewPadding { get; }
WindowPadding viewInsets { get; }
viewMetrics? _viewMetrics = null;
public void OnEnable() {
}

}
public void Update() {
//view metrics marks dirty
this._viewMetrics = null;
}

}
public WindowPadding viewPadding {
get {
return new WindowPadding(this.viewMetrics.padding_left,
this.viewMetrics.padding_top,
this.viewMetrics.padding_right,
this.viewMetrics.padding_bottom);
}
}
public WindowPadding viewInsets {
get {
return new WindowPadding(this.viewMetrics.insets_left,
this.viewMetrics.insets_top,
this.viewMetrics.insets_right,
this.viewMetrics.insets_bottom);
}
}
public viewMetrics viewMetrics {
get {
if (this._viewMetrics != null) {
return this._viewMetrics.Value;
}
#if UNITY_ANDROID
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = Screen.safeArea.x,
padding_top = Screen.safeArea.y,
padding_right = Screen.width - Screen.safeArea.width - Screen.safeArea.x,
padding_bottom = Screen.height - Screen.safeArea.height - Screen.safeArea.y
};
#elif UNITY_WEBGL
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
#elif UNITY_IOS
viewMetrics metrics = IOSGetViewportPadding();
this._viewMetrics = metrics;
#else
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
#endif
return this._viewMetrics.Value;
}
}
#if UNITY_ANDROID
static float AndroidDevicePixelRatio() {
using (

#if UNITY_IOS
[DllImport("__Internal")]
static extern int IOSDeviceScaleFactor();
[DllImport("__Internal")]
static extern viewMetrics IOSGetViewportPadding();
}
}

32
Runtime/engine/UIWidgetsPanel.cs


using System.Collections.Generic;
using Unity.UIWidgets.async;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;

readonly UIWidgetsPanel _uiWidgetsPanel;
bool _needsPaint;
this._padding = new WindowPadding(
Screen.safeArea.x,
Screen.safeArea.y,
Screen.width - Screen.safeArea.width - Screen.safeArea.x,
Screen.height - Screen.safeArea.height - Screen.safeArea.y);
this._padding = this._uiWidgetsPanel.viewPadding;
this._viewInsets = this._uiWidgetsPanel.viewInsets;
}
protected override bool hasFocus() {

Vector2 _lastMouseMove;
HashSet<int> _enteredPointers;
bool _viewMetricsCallbackRegistered;
bool _mouseEntered {
get { return !this._enteredPointers.isEmpty(); }

DisplayMetrics _displayMetrics;
const int mouseButtonNum = 3;
void _handleViewMetricsChanged(string method, List<JSONNode> args) {
this._windowAdapter.onViewMetricsChanged();
this._displayMetrics.Update();
}
protected override void OnEnable() {
base.OnEnable();

this._displayMetrics = DisplayMetricsProvider.provider();
this._displayMetrics.OnEnable();
if (_repaintEvent == null) {
_repaintEvent = new Event {type = EventType.Repaint};
}

}
}
public WindowPadding viewPadding {
get { return this._displayMetrics.viewPadding; }
}
public WindowPadding viewInsets {
get { return this._displayMetrics.viewInsets; }
}
protected virtual Widget createWidget() {
return null;
}

protected virtual void Update() {
this._displayMetrics.Update();
UIWidgetsMessageManager.ensureUIWidgetsMessageManagerIfNeeded();
if (!this._viewMetricsCallbackRegistered) {
this._viewMetricsCallbackRegistered = true;
UIWidgetsMessageManager.instance?.AddChannelMessageDelegate("ViewportMatricsChanged",
this._handleViewMetricsChanged);
}
if (this._mouseEntered) {
if (this._lastMouseMove.x != Input.mousePosition.x || this._lastMouseMove.y != Input.mousePosition.y) {

1
Runtime/material/checkbox.cs


TickerProvider vsync = null,
BoxConstraints additionalConstraints = null
) : base(key: key) {
D.assert(tristate != null);
D.assert(tristate || value != null);
D.assert(activeColor != null);
D.assert(inactiveColor != null);

2
Runtime/widgets/safe_area.cs


}
class SliverSafeArea : StatelessWidget {
public class SliverSafeArea : StatelessWidget {
public SliverSafeArea(
Key key = null,
bool left = true,

81
Runtime/widgets/sliver.cs


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

return new SliverMultiBoxAdaptorElement(this);
}
public float? estimateMaxScrollOffset(
public virtual float? estimateMaxScrollOffset(
SliverConstraints constraints,
int firstIndex,
int lastIndex,

public override void updateRenderObject(BuildContext context, RenderObject renderObjectRaw) {
var renderObject = (RenderSliverFixedExtentList) renderObjectRaw;
renderObject.itemExtent = this.itemExtent;
}
}
public class SliverGrid : SliverMultiBoxAdaptorWidget {
public SliverGrid(
Key key = null,
SliverChildDelegate layoutDelegate = null,
SliverGridDelegate gridDelegate = null
) : base(key: key, del: layoutDelegate) {
D.assert(layoutDelegate != null);
D.assert(gridDelegate != null);
this.gridDelegate = gridDelegate;
}
public static SliverGrid count(
Key key = null,
int? crossAxisCount = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
List<Widget> children = null
) {
return new SliverGrid(
key: key,
layoutDelegate: new SliverChildListDelegate(children ?? new List<Widget> { }),
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
)
);
}
public static SliverGrid extent(
Key key = null,
float? maxCrossAxisExtent = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
List<Widget> children = null
) {
return new SliverGrid(key: key,
layoutDelegate: new SliverChildListDelegate(new List<Widget> { }),
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
));
}
public readonly SliverGridDelegate gridDelegate;
public override RenderObject createRenderObject(BuildContext context) {
SliverMultiBoxAdaptorElement element = context as SliverMultiBoxAdaptorElement;
return new RenderSliverGrid(childManager: element, gridDelegate: this.gridDelegate);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
(renderObject as RenderSliverGrid).gridDelegate = this.gridDelegate;
}
public override float? estimateMaxScrollOffset(
SliverConstraints constraints,
int firstIndex,
int lastIndex,
float leadingScrollOffset,
float trailingScrollOffset
) {
return base.estimateMaxScrollOffset(
constraints,
firstIndex,
lastIndex,
leadingScrollOffset,
trailingScrollOffset
) ?? this.gridDelegate.getLayout(constraints)
.computeMaxScrollOffset(this.del.estimatedChildCount ?? 0);
}
}

70
Runtime/widgets/sliver_persistent_header.cs


bool floating = false
) : base(key: key) {
D.assert(del != null);
this.del = del;
this.layoutDelegate = del;
public readonly SliverPersistentHeaderDelegate del;
public readonly SliverPersistentHeaderDelegate layoutDelegate;
public readonly bool pinned;

if (this.floating && this.pinned) {
return new _SliverFloatingPinnedPersistentHeader(del: this.del);
return new _SliverFloatingPinnedPersistentHeader(layoutDelegate: this.layoutDelegate);
return new _SliverPinnedPersistentHeader(del: this.del);
return new _SliverPinnedPersistentHeader(layoutDelegate: this.layoutDelegate);
return new _SliverFloatingPersistentHeader(del: this.del);
return new _SliverFloatingPersistentHeader(layoutDelegate: this.layoutDelegate);
return new _SliverScrollingPersistentHeader(del: this.del);
return new _SliverScrollingPersistentHeader(layoutDelegate: this.layoutDelegate);
properties.add(new DiagnosticsProperty<SliverPersistentHeaderDelegate>("del", this.del));
properties.add(new DiagnosticsProperty<SliverPersistentHeaderDelegate>("layoutDelegate", this.layoutDelegate));
List<string> flags = new List<string> { };
if (this.pinned) {
flags.Add("pinned");

_SliverPersistentHeaderRenderObjectWidget newWidget =
_newWidget as _SliverPersistentHeaderRenderObjectWidget;
_SliverPersistentHeaderRenderObjectWidget oldWidget = this.widget;
SliverPersistentHeaderDelegate newDelegate = newWidget.del;
SliverPersistentHeaderDelegate oldDelegate = oldWidget.del;
SliverPersistentHeaderDelegate newDelegate = newWidget.layoutDelegate;
SliverPersistentHeaderDelegate oldDelegate = oldWidget.layoutDelegate;
if (newDelegate != oldDelegate &&
(newDelegate.GetType() != oldDelegate.GetType() || newDelegate.shouldRebuild(oldDelegate))) {
(this.renderObject as _RenderSliverPersistentHeaderForWidgetsMixin).triggerRebuild();

this.owner.buildScope(this,
() => {
this.child = this.updateChild(this.child,
this.widget.del.build(this, shrinkOffset, overlapsContent), null);
this.widget.layoutDelegate.build(this, shrinkOffset, overlapsContent), null);
});
}

abstract class _SliverPersistentHeaderRenderObjectWidget : RenderObjectWidget {
public _SliverPersistentHeaderRenderObjectWidget(
Key key = null,
SliverPersistentHeaderDelegate del = null
SliverPersistentHeaderDelegate layoutDelegate = null
D.assert(del != null);
this.del = del;
D.assert(layoutDelegate != null);
this.layoutDelegate = layoutDelegate;
public readonly SliverPersistentHeaderDelegate del;
public readonly SliverPersistentHeaderDelegate layoutDelegate;
public override Element createElement() {
return new _SliverPersistentHeaderElement(this);

public override void debugFillProperties(DiagnosticPropertiesBuilder description) {
base.debugFillProperties(description);
description.add(new DiagnosticsProperty<SliverPersistentHeaderDelegate>("del", this.del));
description.add(new DiagnosticsProperty<SliverPersistentHeaderDelegate>("layoutDelegate", this.layoutDelegate));
}
}

class _SliverScrollingPersistentHeader : _SliverPersistentHeaderRenderObjectWidget {
public _SliverScrollingPersistentHeader(
Key key = null,
SliverPersistentHeaderDelegate del = null
) : base(key: key, del: del) {
SliverPersistentHeaderDelegate layoutDelegate = null
) : base(key: key, layoutDelegate: layoutDelegate) {
}
public override RenderObject createRenderObject(BuildContext context) {

_SliverPersistentHeaderElement _ele;
public override float? minExtent {
get { return this._element.widget.del.minExtent; }
get { return this._element.widget.layoutDelegate.minExtent; }
get { return this._element.widget.del.maxExtent; }
get { return this._element.widget.layoutDelegate.maxExtent; }
}
protected override void updateChild(float shrinkOffset, bool overlapsContent) {

class _SliverPinnedPersistentHeader : _SliverPersistentHeaderRenderObjectWidget {
public _SliverPinnedPersistentHeader(
Key key = null,
SliverPersistentHeaderDelegate del = null
) : base(key: key, del: del) {
SliverPersistentHeaderDelegate layoutDelegate = null
) : base(key: key, layoutDelegate: layoutDelegate) {
}
public override RenderObject createRenderObject(BuildContext context) {

_SliverPersistentHeaderElement _ele;
public override float? minExtent {
get { return this._element.widget.del.minExtent; }
get { return this._element.widget.layoutDelegate.minExtent; }
get { return this._element.widget.del.maxExtent; }
get { return this._element.widget.layoutDelegate.maxExtent; }
}
protected override void updateChild(float shrinkOffset, bool overlapsContent) {

class _SliverFloatingPersistentHeader : _SliverPersistentHeaderRenderObjectWidget {
public _SliverFloatingPersistentHeader(
Key key = null,
SliverPersistentHeaderDelegate del = null
) : base(key: key, del: del) {
SliverPersistentHeaderDelegate layoutDelegate = null
) : base(key: key, layoutDelegate: layoutDelegate) {
ret.snapConfiguration = this.del.snapConfiguration;
ret.snapConfiguration = this.layoutDelegate.snapConfiguration;
return ret;
}

renderObject.snapConfiguration = this.del.snapConfiguration;
renderObject.snapConfiguration = this.layoutDelegate.snapConfiguration;
}
}

_SliverPersistentHeaderElement _ele;
public override float? minExtent {
get { return this._element.widget.del.minExtent; }
get { return this._element.widget.layoutDelegate.minExtent; }
get { return this._element.widget.del.maxExtent; }
get { return this._element.widget.layoutDelegate.maxExtent; }
}
protected override void updateChild(float shrinkOffset, bool overlapsContent) {

class _SliverFloatingPinnedPersistentHeader : _SliverPersistentHeaderRenderObjectWidget {
public _SliverFloatingPinnedPersistentHeader(
Key key = null,
SliverPersistentHeaderDelegate del = null
) : base(key: key, del: del) {
SliverPersistentHeaderDelegate layoutDelegate = null
) : base(key: key, layoutDelegate: layoutDelegate) {
ret.snapConfiguration = this.del.snapConfiguration;
ret.snapConfiguration = this.layoutDelegate.snapConfiguration;
return ret;
}

renderObject.snapConfiguration = this.del.snapConfiguration;
renderObject.snapConfiguration = this.layoutDelegate.snapConfiguration;
}
}

_SliverPersistentHeaderElement _ele;
public override float? minExtent {
get { return this._element.widget.del.minExtent; }
get { return this._element.widget.layoutDelegate.minExtent; }
get { return this._element.widget.del.maxExtent; }
get { return this._element.widget.layoutDelegate.maxExtent; }
}
protected override void updateChild(float shrinkOffset, bool overlapsContent) {

4
Samples/UIWidgetsGallery/gallery/demo.cs


void _showApiDocumentation(BuildContext context) {
string url = this.demos[DefaultTabController.of(context).index].documentationUrl;
if (url != null) {
// TODO: find Unity equivalent
// Open the URL in browser
// launch(url, forceWebView: true);
Application.OpenURL(url);
}
}

18
Samples/UIWidgetsGallery/gallery/demos.cs


public static partial class DemoUtils {
static List<GalleryDemo> _buildGalleryDemos() {
List<GalleryDemo> galleryDemos = new List<GalleryDemo> {
// // Demos
// new GalleryDemo(
// title: "Shrine",
// subtitle: "Basic shopping app",
// icon: GalleryIcons.shrine,
// category: GalleryDemoCategory._kDemos,
// routeName: ShrineDemo.routeName,
// buildRoute: (BuildContext context) => new ShrineDemo()
// ),
// Demos
new GalleryDemo(
title: "Shrine",
subtitle: "Basic shopping app",
icon: GalleryIcons.shrine,
category: DemoUtils._kDemos,
routeName: ShrineDemo.routeName,
buildRoute: (BuildContext context) => new ShrineDemo()
),
new GalleryDemo(
title: "Contact profile",
subtitle: "Address book entry with a flexible appbar",

34
Runtime/Plugins/platform/ios/UIWidgetsViewController.h


#ifndef PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_
#define PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_
#import <UIKit/UIKit.h>
#include "UIWidgetsTextInputDelegate.h"
struct viewPadding
{
float top;
float bottom;
float left;
float right;
};
struct viewMetrics
{
float insets_top;
float insets_bottom;
float insets_left;
float insets_right;
float padding_top;
float padding_bottom;
float padding_left;
float padding_right;
};
@interface UIWidgetsViewController : NSObject
@property viewPadding padding;
@property viewPadding viewInsets;
@end
#endif // PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_

26
Runtime/Plugins/platform/ios/UIWidgetsViewController.h.meta


fileFormatVersion: 2
guid: a797fb0a2ddb84d4e8ac7f6da5d70819
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

108
Runtime/Plugins/platform/ios/UIWidgetsViewController.mm


#include "UIWidgetsViewController.h"
#include "UIWidgetsMessageManager.h"
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
@implementation UIWidgetsViewController {
}
@synthesize viewInsets;
@synthesize padding;
- (instancetype)init {
self = [super init];
if (self) {
viewInsets.bottom = 0;
viewInsets.top = 0;
viewInsets.left = 0;
viewInsets.right = 0;
CGFloat scale = [[UIScreen mainScreen] scale];
if (@available(iOS 11, *)) {
padding.bottom = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom * scale;
padding.top = [UIApplication sharedApplication].keyWindow.safeAreaInsets.top * scale;
padding.left = [UIApplication sharedApplication].keyWindow.safeAreaInsets.left * scale;
padding.right = [UIApplication sharedApplication].keyWindow.safeAreaInsets.right * scale;
} else {
CGRect statusFrame = [UIApplication sharedApplication].statusBarFrame;
padding.bottom = 0;
padding.top = statusFrame.size.height * scale;
padding.left = 0;
padding.right = 0;
}
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(keyboardWillChangeFrame:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
}
return self;
}
-(void)keyboardWillBeHidden:(NSNotification*)notification {
viewInsets.bottom = 0;
CGFloat scale = [UIScreen mainScreen].scale;
if (@available(iOS 11, *)) {
CGFloat cur_padding = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom * scale;
padding.bottom = cur_padding;
} else {
CGRect statusFrame = [UIApplication sharedApplication].statusBarFrame;
CGFloat cur_padding = statusFrame.size.height * scale;
padding.top = cur_padding;
}
UIWidgetsMethodMessage(@"ViewportMatricsChanged", @"UIWidgetViewController.keyboardHide", @[]);
}
-(void)keyboardWillChangeFrame:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];
CGFloat bottom = CGRectGetHeight([[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]);
CGFloat scale = [UIScreen mainScreen].scale;
viewInsets.bottom = bottom * scale;
padding.bottom = 0;
UIWidgetsMethodMessage(@"ViewportMatricsChanged", @"UIWidgetViewController.keyboardHide", @[]);
}
-(void)tryLaunch {
}
+ (instancetype)sharedInstance {
static UIWidgetsViewController *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[UIWidgetsViewController alloc] init];
});
return sharedInstance;
}
@end
extern "C"
{
viewMetrics IOSGetViewportPadding()
{
viewMetrics metrics;
viewPadding insets = [[UIWidgetsViewController sharedInstance] viewInsets];
viewPadding padding = [[UIWidgetsViewController sharedInstance] padding];
metrics.insets_bottom = insets.bottom;
metrics.insets_top = insets.top;
metrics.insets_left = insets.left;
metrics.insets_right = insets.right;
metrics.padding_bottom = padding.bottom;
metrics.padding_top = padding.top;
metrics.padding_left = padding.left;
metrics.padding_right = padding.right;
return metrics;
}
}

36
Runtime/Plugins/platform/ios/UIWidgetsViewController.mm.meta


fileFormatVersion: 2
guid: fc3d8a9d616f147929ae9b8898fa01bf
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings: {}
- first:
tvOS: tvOS
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:

451
Runtime/rendering/sliver_grid.cs


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

11
Runtime/rendering/sliver_grid.cs.meta


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

553
Runtime/widgets/heroes.cs


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

3
Runtime/widgets/heroes.cs.meta


fileFormatVersion: 2
guid: ae21d125110c4c989fd2ce9e5a0bc1c0
timeCreated: 1554263028

8
Samples/UIWidgetsGallery/demo/shrine.meta


fileFormatVersion: 2
guid: 2621a6f94ad8a4b5ab7199025967dc90
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

40
Samples/UIWidgetsGallery/demo/shrine_demo.cs


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

3
Samples/UIWidgetsGallery/demo/shrine_demo.cs.meta


fileFormatVersion: 2
guid: 5902905cca7447d2aa1fe5ae7f6c5cbc
timeCreated: 1553239620

8
Tests/Resources/people.meta


fileFormatVersion: 2
guid: 8988da6435b0e414da67d5bb45802754
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

280
Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs


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

3
Samples/UIWidgetsGallery/demo/shrine/shrine_data.cs.meta


fileFormatVersion: 2
guid: f29bb63cff3148cbb3ef3be8196d5709
timeCreated: 1553240837

410
Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs


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

11
Samples/UIWidgetsGallery/demo/shrine/shrine_home.cs.meta


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

3
Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs.meta


fileFormatVersion: 2
guid: b0720924e140457dbc8626755c82f3ba
timeCreated: 1553244438

156
Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs


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

3
Samples/UIWidgetsGallery/demo/shrine/shrine_page.cs.meta


fileFormatVersion: 2
guid: 81f9ca5ad3e848f4889059abd3037d17
timeCreated: 1553246179

98
Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs


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

3
Samples/UIWidgetsGallery/demo/shrine/shrine_theme.cs.meta


fileFormatVersion: 2
guid: 468619e1fd4f4437ba3f0929e269aab4
timeCreated: 1553241961

153
Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs


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

3
Samples/UIWidgetsGallery/demo/shrine/shrine_types.cs.meta


fileFormatVersion: 2
guid: 924c1662fb504687af28a4f05901a20a
timeCreated: 1553240139

341
Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs


using System.Collections.Generic;
using System.Linq;
using com.unity.uiwidgets.Runtime.rendering;
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 Image = Unity.UIWidgets.widgets.Image;
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) {
return 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() {
return 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) {
return (ShrineOrderRoute) ModalRoute.of(context);
}
}
}

1001
Tests/Resources/people/ali_landscape.png
文件差异内容过多而无法显示
查看文件

88
Tests/Resources/people/ali_landscape.png.meta


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:

8
Tests/Resources/people/square.meta


fileFormatVersion: 2
guid: 321c11a98ef1c452ba9bf4fad8ac67fe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

457
Tests/Resources/people/square/ali.png

之前 之后
宽度: 300  |  高度: 300  |  大小: 127 KiB

88
Tests/Resources/people/square/ali.png.meta


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:

509
Tests/Resources/people/square/peter.png

之前 之后
宽度: 300  |  高度: 300  |  大小: 161 KiB

88
Tests/Resources/people/square/peter.png.meta


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:

698
Tests/Resources/people/square/sandra.png

之前 之后
宽度: 300  |  高度: 300  |  大小: 165 KiB

88
Tests/Resources/people/square/sandra.png.meta


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:

393
Tests/Resources/people/square/stella.png

之前 之后
宽度: 300  |  高度: 300  |  大小: 128 KiB

88
Tests/Resources/people/square/stella.png.meta


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:

574
Tests/Resources/people/square/trevor.png

之前 之后
宽度: 300  |  高度: 300  |  大小: 156 KiB

88
Tests/Resources/people/square/trevor.png.meta


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:

8
scripts/node_modules.meta


fileFormatVersion: 2
guid: 7d78b565ea82c414a9c59aa6ccd9bd2c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存