Xingwei Zhu
3 年前
当前提交
6b65f2d7
共有 25 个文件被更改,包括 3367 次插入 和 0 次删除
-
1001AwesomeUIWidgets/Assets/Scenes/ItemPickerRoom.unity
-
7AwesomeUIWidgets/Assets/Scenes/ItemPickerRoom.unity.meta
-
8AwesomeUIWidgets/Assets/StreamingAssets/heroSample.meta
-
20AwesomeUIWidgets/Assets/Scripts/heroSample/HeroSamplePanel.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/HeroSamplePanel.cs.meta
-
51AwesomeUIWidgets/Assets/Scripts/heroSample/heroItem.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/heroItem.cs.meta
-
575AwesomeUIWidgets/Assets/Scripts/heroSample/home.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/home.cs.meta
-
64AwesomeUIWidgets/Assets/Scripts/heroSample/radial_expansion.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/radial_expansion.cs.meta
-
170AwesomeUIWidgets/Assets/Scripts/heroSample/sections.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/sections.cs.meta
-
244AwesomeUIWidgets/Assets/Scripts/heroSample/widgets.cs
-
3AwesomeUIWidgets/Assets/Scripts/heroSample/widgets.cs.meta
-
220AwesomeUIWidgets/Assets/StreamingAssets/heroSample/capture2.jpeg
-
7AwesomeUIWidgets/Assets/StreamingAssets/heroSample/capture2.jpeg.meta
-
48AwesomeUIWidgets/Assets/StreamingAssets/heroSample/cube2.jpeg
-
7AwesomeUIWidgets/Assets/StreamingAssets/heroSample/cube2.jpeg.meta
-
57AwesomeUIWidgets/Assets/StreamingAssets/heroSample/cylinder2.jpeg
-
7AwesomeUIWidgets/Assets/StreamingAssets/heroSample/cylinder2.jpeg.meta
-
856AwesomeUIWidgets/Assets/StreamingAssets/heroSample/sphere2.jpeg
-
7AwesomeUIWidgets/Assets/StreamingAssets/heroSample/sphere2.jpeg.meta
1001
AwesomeUIWidgets/Assets/Scenes/ItemPickerRoom.unity
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: 11b1321b95bd0474eb15e274fe84fa78 |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 7f357fb15b3ed4a3e9e7bf2273cbf351 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using uiwidgets; |
|||
using Unity.UIWidgets.engine; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery |
|||
{ |
|||
public class HeroSamplePanel : UIWidgetsPanel |
|||
{ |
|||
protected override void main() |
|||
{ |
|||
//ui_.runApp(new Container(color: Colors.blue.withAlpha(128)));
|
|||
ui_.runApp(new MaterialApp( |
|||
color: Colors.blue.withAlpha(128), |
|||
title: "Hero Sample", |
|||
home: new AnimationDemoHome() |
|||
)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ffe87af2c0844a31b447cd89ca659cce |
|||
timeCreated: 1626763295 |
|
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.gallery |
|||
{ |
|||
public class heroItem : MonoBehaviour |
|||
{ |
|||
private List<GameObject> items = new List<GameObject>(); |
|||
|
|||
private static int _previousHeroType = 0; |
|||
public static int heroType = 0; |
|||
|
|||
void Start() |
|||
{ |
|||
var cube = transform.Find("Cube").gameObject; |
|||
var sphere = transform.Find("Sphere").gameObject; |
|||
var cylinder = transform.Find("Cylinder").gameObject; |
|||
var capsule = transform.Find("Capsule").gameObject; |
|||
|
|||
items.Add(cube); |
|||
items.Add(sphere); |
|||
items.Add(capsule); |
|||
items.Add(cylinder); |
|||
|
|||
UpdateItem(); |
|||
} |
|||
|
|||
void UpdateItem() |
|||
{ |
|||
for (var i = 0; i < items.Count; i++) |
|||
{ |
|||
items[i].SetActive(i == heroType); |
|||
} |
|||
} |
|||
|
|||
void Update() |
|||
{ |
|||
if (heroType != _previousHeroType) |
|||
{ |
|||
_previousHeroType = heroType; |
|||
UpdateItem(); |
|||
} |
|||
|
|||
transform.Rotate( |
|||
0 * Time.deltaTime, |
|||
60f * Time.deltaTime, |
|||
0 * Time.deltaTime |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0366b7a501914ae1855dce19103c98f5 |
|||
timeCreated: 1626776068 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.physics; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using Rect = Unity.UIWidgets.ui.Rect; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class AnimationHomeUtils |
|||
{ |
|||
public static readonly Color _kAppBackgroundColor = Colors.blue.withAlpha(128); |
|||
public static readonly TimeSpan _kScrollDuration = new TimeSpan(0, 0, 0, 0, 100); |
|||
public static readonly Curve _kScrollCurve = Curves.fastOutSlowIn; |
|||
public const float _kAppBarMinHeight = 90.0f; |
|||
public const float _kAppBarMidHeight = 256.0f; |
|||
} |
|||
|
|||
class _RenderStatusBarPaddingSliver : RenderSliver { |
|||
public _RenderStatusBarPaddingSliver( |
|||
float? maxHeight = null, |
|||
float? scrollFactor = null |
|||
) { |
|||
D.assert(maxHeight >= 0.0f); |
|||
D.assert(scrollFactor >= 1.0f); |
|||
this._maxHeight = maxHeight; |
|||
this._scrollFactor = scrollFactor; |
|||
} |
|||
|
|||
public float? maxHeight { |
|||
get { return this._maxHeight; } |
|||
set { |
|||
D.assert(this.maxHeight >= 0.0f); |
|||
if (this._maxHeight == value) { |
|||
return; |
|||
} |
|||
|
|||
this._maxHeight = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
float? _maxHeight; |
|||
|
|||
public float? scrollFactor { |
|||
get { return this._scrollFactor; } |
|||
set { |
|||
D.assert(this.scrollFactor >= 1.0f); |
|||
if (this._scrollFactor == value) { |
|||
return; |
|||
} |
|||
|
|||
this._scrollFactor = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
float? _scrollFactor; |
|||
|
|||
protected override void performLayout() { |
|||
float? height = |
|||
(this.maxHeight - this.constraints.scrollOffset / this.scrollFactor)?.clamp(0.0f, |
|||
this.maxHeight ?? 0.0f); |
|||
this.geometry = new SliverGeometry( |
|||
paintExtent: Mathf.Min(height ?? 0.0f, this.constraints.remainingPaintExtent), |
|||
scrollExtent: this.maxHeight ?? 0.0f, |
|||
maxPaintExtent: this.maxHeight ?? 0.0f |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _StatusBarPaddingSliver : SingleChildRenderObjectWidget { |
|||
public _StatusBarPaddingSliver( |
|||
Key key = null, |
|||
float? maxHeight = null, |
|||
float scrollFactor = 5.0f |
|||
) : base(key: key) { |
|||
D.assert(maxHeight != null && maxHeight >= 0.0f); |
|||
D.assert(scrollFactor >= 1.0f); |
|||
this.maxHeight = maxHeight; |
|||
this.scrollFactor = scrollFactor; |
|||
} |
|||
|
|||
public readonly float? maxHeight; |
|||
public readonly float scrollFactor; |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new _RenderStatusBarPaddingSliver( |
|||
maxHeight: this.maxHeight, |
|||
scrollFactor: this.scrollFactor |
|||
); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject _renderObject) { |
|||
_RenderStatusBarPaddingSliver renderObject = _renderObject as _RenderStatusBarPaddingSliver; |
|||
renderObject.maxHeight = this.maxHeight; |
|||
renderObject.scrollFactor = this.scrollFactor; |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder description) { |
|||
base.debugFillProperties(description); |
|||
description.add(new FloatProperty("maxHeight", this.maxHeight)); |
|||
description.add(new FloatProperty("scrollFactor", this.scrollFactor)); |
|||
} |
|||
} |
|||
|
|||
class _SliverAppBarDelegate : SliverPersistentHeaderDelegate { |
|||
public _SliverAppBarDelegate( |
|||
float minHeight, |
|||
float maxHeight, |
|||
Widget child |
|||
) { |
|||
this.minHeight = minHeight; |
|||
this.maxHeight = maxHeight; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly float minHeight; |
|||
public readonly float maxHeight; |
|||
public readonly Widget child; |
|||
|
|||
public override float? minExtent { |
|||
get { return this.minHeight; } |
|||
} |
|||
|
|||
public override float? maxExtent { |
|||
get { return Mathf.Max(this.maxHeight, this.minHeight); } |
|||
} |
|||
|
|||
public override Widget build(BuildContext context, float shrinkOffset, bool overlapsContent) { |
|||
return SizedBox.expand(child: this.child); |
|||
} |
|||
|
|||
public override bool shouldRebuild(SliverPersistentHeaderDelegate _oldDelegate) { |
|||
_SliverAppBarDelegate oldDelegate = _oldDelegate as _SliverAppBarDelegate; |
|||
return this.maxHeight != oldDelegate.maxHeight |
|||
|| this.minHeight != oldDelegate.minHeight |
|||
|| this.child != oldDelegate.child; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "_SliverAppBarDelegate"; |
|||
} |
|||
} |
|||
|
|||
class _AllSectionsLayout : MultiChildLayoutDelegate { |
|||
public _AllSectionsLayout( |
|||
Alignment translation, |
|||
float tColumnToRow, |
|||
float tCollapsed, |
|||
int cardCount, |
|||
float selectedIndex |
|||
) { |
|||
this.translation = translation; |
|||
this.tColumnToRow = tColumnToRow; |
|||
this.tCollapsed = tCollapsed; |
|||
this.cardCount = cardCount; |
|||
this.selectedIndex = selectedIndex; |
|||
} |
|||
|
|||
public readonly Alignment translation; |
|||
public readonly float tColumnToRow; |
|||
public readonly float tCollapsed; |
|||
public readonly int cardCount; |
|||
public readonly float selectedIndex; |
|||
|
|||
Rect _interpolateRect(Rect begin, Rect end) { |
|||
return Rect.lerp(begin, end, this.tColumnToRow); |
|||
} |
|||
|
|||
Offset _interpolatePoint(Offset begin, Offset end) { |
|||
return Offset.lerp(begin, end, this.tColumnToRow); |
|||
} |
|||
|
|||
public override void performLayout(Size size) { |
|||
Debug.Log("perform layout = " + size.ToString() + " " + selectedIndex + " " + tColumnToRow); |
|||
float columnCardX = size.width / 5.0f; |
|||
float columnCardWidth = size.width - columnCardX; |
|||
float columnCardHeight = size.height / this.cardCount; |
|||
float rowCardWidth = size.width; |
|||
Offset offset = Offset.zero; //this.translation.alongSize(size);
|
|||
float columnCardY = 0.0f; |
|||
float rowCardX = -(this.selectedIndex * rowCardWidth); |
|||
|
|||
float columnTitleX = size.width / 10.0f; |
|||
float rowTitleWidth = size.width * ((1 + this.tCollapsed) / 2.25f); |
|||
float rowTitleX = (size.width - rowTitleWidth) / 2.0f - this.selectedIndex * rowTitleWidth; |
|||
|
|||
const float paddedSectionIndicatorWidth = AnimationWidgetsUtils.kSectionIndicatorWidth + 8.0f; |
|||
float rowIndicatorWidth = paddedSectionIndicatorWidth + |
|||
(1.0f - this.tCollapsed) * (rowTitleWidth - paddedSectionIndicatorWidth); |
|||
float rowIndicatorX = (size.width - rowIndicatorWidth) / 2.0f - this.selectedIndex * rowIndicatorWidth; |
|||
|
|||
for (int index = 0; index < this.cardCount; index++) { |
|||
Rect columnCardRect = Rect.fromLTWH(columnCardX, columnCardY, columnCardWidth, columnCardHeight); |
|||
Rect rowCardRect = Rect.fromLTWH(rowCardX, 0.0f, rowCardWidth, size.height); |
|||
Rect cardRect = this._interpolateRect(columnCardRect, rowCardRect).shift(offset); |
|||
|
|||
if (index == 0) |
|||
{ |
|||
Debug.Log("first card rect = " + cardRect + " " + columnCardRect + " " + rowCardRect); |
|||
} |
|||
string cardId = $"card{index}"; |
|||
if (this.hasChild(cardId)) { |
|||
this.layoutChild(cardId, BoxConstraints.tight(cardRect.size)); |
|||
this.positionChild(cardId, cardRect.topLeft); |
|||
} |
|||
|
|||
Size titleSize = this.layoutChild($"title{index}", BoxConstraints.loose(cardRect.size)); |
|||
float columnTitleY = columnCardRect.centerLeft.dy - titleSize.height / 2.0f; |
|||
float rowTitleY = rowCardRect.centerLeft.dy - titleSize.height / 2.0f; |
|||
float centeredRowTitleX = rowTitleX + (rowTitleWidth - titleSize.width) / 2.0f; |
|||
Offset columnTitleOrigin = new Offset(columnTitleX, columnTitleY); |
|||
Offset rowTitleOrigin = new Offset(centeredRowTitleX, rowTitleY); |
|||
Offset titleOrigin = this._interpolatePoint(columnTitleOrigin, rowTitleOrigin); |
|||
this.positionChild($"title{index}", titleOrigin + offset); |
|||
|
|||
Size indicatorSize = this.layoutChild($"indicator{index}", BoxConstraints.loose(cardRect.size)); |
|||
float columnIndicatorX = cardRect.centerRight.dx - indicatorSize.width - 16.0f; |
|||
float columnIndicatorY = cardRect.bottomRight.dy - indicatorSize.height - 16.0f; |
|||
Offset columnIndicatorOrigin = new Offset(columnIndicatorX, columnIndicatorY); |
|||
Rect titleRect = Rect.fromPoints(titleOrigin, titleSize.bottomRight(titleOrigin)); |
|||
float centeredRowIndicatorX = rowIndicatorX + (rowIndicatorWidth - indicatorSize.width) / 2.0f; |
|||
float rowIndicatorY = titleRect.bottomCenter.dy + 16.0f; |
|||
Offset rowIndicatorOrigin = new Offset(centeredRowIndicatorX, rowIndicatorY); |
|||
Offset indicatorOrigin = this._interpolatePoint(columnIndicatorOrigin, rowIndicatorOrigin); |
|||
this.positionChild($"indicator{index}", indicatorOrigin + offset); |
|||
|
|||
columnCardY += columnCardHeight; |
|||
rowCardX += rowCardWidth; |
|||
rowTitleX += rowTitleWidth; |
|||
rowIndicatorX += rowIndicatorWidth; |
|||
} |
|||
} |
|||
|
|||
public override bool shouldRelayout(MultiChildLayoutDelegate _oldDelegate) { |
|||
_AllSectionsLayout oldDelegate = _oldDelegate as _AllSectionsLayout; |
|||
return this.tColumnToRow != oldDelegate.tColumnToRow |
|||
|| this.cardCount != oldDelegate.cardCount |
|||
|| this.selectedIndex != oldDelegate.selectedIndex; |
|||
} |
|||
} |
|||
|
|||
class _AllSectionsView : AnimatedWidget { |
|||
public _AllSectionsView( |
|||
Key key = null, |
|||
int? sectionIndex = null, |
|||
List<Section> sections = null, |
|||
ValueNotifier<float> selectedIndex = null, |
|||
float? minHeight = null, |
|||
float? midHeight = null, |
|||
float? maxHeight = null, |
|||
List<Widget> sectionCards = null |
|||
) : base(key: key, listenable: selectedIndex) { |
|||
sectionCards = sectionCards ?? new List<Widget>(); |
|||
D.assert(sections != null); |
|||
D.assert(sectionCards.Count == sections.Count); |
|||
D.assert(sectionIndex >= 0 && sectionIndex < sections.Count); |
|||
D.assert(selectedIndex != null); |
|||
D.assert(selectedIndex.value >= 0.0f && (float) selectedIndex.value < sections.Count); |
|||
this.sectionIndex = sectionIndex; |
|||
this.sections = sections; |
|||
this.selectedIndex = selectedIndex; |
|||
this.minHeight = minHeight; |
|||
this.midHeight = midHeight; |
|||
this.maxHeight = maxHeight; |
|||
this.sectionCards = sectionCards; |
|||
} |
|||
|
|||
public readonly int? sectionIndex; |
|||
public readonly List<Section> sections; |
|||
public readonly ValueNotifier<float> selectedIndex; |
|||
public readonly float? minHeight; |
|||
public readonly float? midHeight; |
|||
public readonly float? maxHeight; |
|||
public readonly List<Widget> sectionCards; |
|||
|
|||
float _selectedIndexDelta(int index) { |
|||
return (index - this.selectedIndex.value).abs().clamp(0.0f, 1.0f); |
|||
} |
|||
|
|||
Widget _build(BuildContext context, BoxConstraints constraints) { |
|||
Size size = constraints.biggest; |
|||
|
|||
float? tColumnToRow = |
|||
1.0f - ((size.height - this.midHeight) / |
|||
(this.maxHeight - this.midHeight))?.clamp(0.0f, 1.0f); |
|||
|
|||
|
|||
float? tCollapsed = |
|||
1.0f - ((size.height - this.minHeight) / |
|||
(this.midHeight - this.minHeight))?.clamp(0.0f, 1.0f); |
|||
|
|||
float _indicatorOpacity(int index) { |
|||
return 1.0f - this._selectedIndexDelta(index) * 0.5f; |
|||
} |
|||
|
|||
float? _titleOpacity(int index) { |
|||
return 1.0f - this._selectedIndexDelta(index) * tColumnToRow * 0.5f; |
|||
} |
|||
|
|||
float? _titleScale(int index) { |
|||
return 1.0f - this._selectedIndexDelta(index) * tColumnToRow * 0.15f; |
|||
} |
|||
|
|||
List<Widget> children = new List<Widget>(this.sectionCards); |
|||
|
|||
for (int index = 0; index < this.sections.Count; index++) { |
|||
Section section = this.sections[index]; |
|||
children.Add(new LayoutId( |
|||
id: $"title{index}", |
|||
child: new SectionTitle( |
|||
section: section, |
|||
scale: _titleScale(index), |
|||
opacity: _titleOpacity(index) |
|||
) |
|||
)); |
|||
} |
|||
|
|||
for (int index = 0; index < this.sections.Count; index++) { |
|||
children.Add(new LayoutId( |
|||
id: $"indicator{index}", |
|||
child: new SectionIndicator( |
|||
opacity: _indicatorOpacity(index) |
|||
) |
|||
)); |
|||
} |
|||
|
|||
return new CustomMultiChildLayout( |
|||
layoutDelegate: new _AllSectionsLayout( |
|||
translation: new Alignment((this.selectedIndex.value - this.sectionIndex) * 2.0f - 1.0f ?? 0.0f, |
|||
-1.0f), |
|||
tColumnToRow: tColumnToRow ?? 0.0f, |
|||
tCollapsed: tCollapsed ?? 0.0f, |
|||
cardCount: this.sections.Count, |
|||
selectedIndex: this.selectedIndex.value |
|||
), |
|||
children: children |
|||
); |
|||
} |
|||
|
|||
protected override Widget build(BuildContext context) { |
|||
return new LayoutBuilder(builder: this._build); |
|||
} |
|||
} |
|||
|
|||
class _SnappingScrollPhysics : ClampingScrollPhysics { |
|||
public _SnappingScrollPhysics( |
|||
ScrollPhysics parent = null, |
|||
float? midScrollOffset = null |
|||
) : base(parent: parent) { |
|||
D.assert(midScrollOffset != null); |
|||
this.midScrollOffset = midScrollOffset ?? 0.0f; |
|||
} |
|||
|
|||
public readonly float midScrollOffset; |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new _SnappingScrollPhysics(parent: this.buildParent(ancestor), |
|||
midScrollOffset: this.midScrollOffset); |
|||
} |
|||
|
|||
Simulation _toMidScrollOffsetSimulation(float offset, float dragVelocity) { |
|||
float velocity = Mathf.Max(dragVelocity, this.minFlingVelocity); |
|||
return new ScrollSpringSimulation(this.spring, offset, this.midScrollOffset, velocity, |
|||
tolerance: this.tolerance); |
|||
} |
|||
|
|||
Simulation _toZeroScrollOffsetSimulation(float offset, float dragVelocity) { |
|||
float velocity = Mathf.Max(dragVelocity, this.minFlingVelocity); |
|||
return new ScrollSpringSimulation(this.spring, offset, 0.0f, velocity, tolerance: this.tolerance); |
|||
} |
|||
|
|||
public override Simulation createBallisticSimulation(ScrollMetrics position, float dragVelocity) { |
|||
Simulation simulation = base.createBallisticSimulation(position, dragVelocity); |
|||
float offset = position.pixels; |
|||
|
|||
if (simulation != null) { |
|||
float simulationEnd = simulation.x(float.PositiveInfinity); |
|||
if (simulationEnd >= this.midScrollOffset) { |
|||
return simulation; |
|||
} |
|||
|
|||
if (dragVelocity > 0.0f) { |
|||
return this._toMidScrollOffsetSimulation(offset, dragVelocity); |
|||
} |
|||
|
|||
if (dragVelocity < 0.0f) { |
|||
return this._toZeroScrollOffsetSimulation(offset, dragVelocity); |
|||
} |
|||
} |
|||
else { |
|||
float snapThreshold = this.midScrollOffset / 2.0f; |
|||
if (offset >= snapThreshold && offset < this.midScrollOffset) { |
|||
return this._toMidScrollOffsetSimulation(offset, dragVelocity); |
|||
} |
|||
|
|||
if (offset > 0.0f && offset < snapThreshold) { |
|||
return this._toZeroScrollOffsetSimulation(offset, dragVelocity); |
|||
} |
|||
} |
|||
|
|||
return simulation; |
|||
} |
|||
} |
|||
|
|||
public class AnimationDemoHome : StatefulWidget { |
|||
public AnimationDemoHome(Key key = null) : base(key: key) { |
|||
} |
|||
|
|||
public const string routeName = "/animation"; |
|||
|
|||
public override State createState() { |
|||
return new _AnimationDemoHomeState(); |
|||
} |
|||
} |
|||
|
|||
class _AnimationDemoHomeState : State<AnimationDemoHome> { |
|||
ScrollController _scrollController = new ScrollController(); |
|||
PageController _headingPageController = new PageController(); |
|||
PageController _detailsPageController = new PageController(); |
|||
ScrollPhysics _headingScrollPhysics = new NeverScrollableScrollPhysics(); |
|||
ValueNotifier<float> selectedIndex = new ValueNotifier<float>(0.0f); |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new Scaffold( |
|||
backgroundColor: AnimationHomeUtils._kAppBackgroundColor, |
|||
body: new Builder( |
|||
builder: this._buildBody |
|||
) |
|||
); |
|||
} |
|||
|
|||
bool _handleScrollNotification(ScrollNotification notification, float midScrollOffset) { |
|||
Debug.Log("1111 = " + _headingPageController.ToString() + " " + _headingPageController.page); |
|||
if (notification.depth == 0 && notification is ScrollUpdateNotification) { |
|||
ScrollPhysics physics = this._scrollController.position.pixels >= midScrollOffset |
|||
? (ScrollPhysics) new PageScrollPhysics() |
|||
: new NeverScrollableScrollPhysics(); |
|||
if (physics != this._headingScrollPhysics) { |
|||
this.setState(() => { this._headingScrollPhysics = physics; }); |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool _handlePageNotification(ScrollNotification notification, PageController leader, PageController follower) { |
|||
if (notification.depth == 0 && notification is ScrollUpdateNotification) { |
|||
this.selectedIndex.value = leader.page; |
|||
//Debug.Log("selected change to Index =" + selectedIndex.value);
|
|||
if (follower.page != leader.page) { |
|||
follower.position.jumpTo(leader.position.pixels); // ignore: deprecated_member_use
|
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
List<Widget> _allHeadingItems(float maxHeight, float midScrollOffset) { |
|||
List<Widget> sectionCards = new List<Widget> { }; |
|||
for (int index = 0; index < AnimationSectionsUtils.allSections.Count; index++) { |
|||
sectionCards.Add(new LayoutId( |
|||
id: $"card{index}", |
|||
child: new SectionCard(section: AnimationSectionsUtils.allSections[index]) |
|||
)); |
|||
} |
|||
|
|||
List<Widget> headings = new List<Widget> { }; |
|||
for (int index = 0; index < AnimationSectionsUtils.allSections.Count; index++) { |
|||
headings.Add(new Container( |
|||
color: AnimationHomeUtils._kAppBackgroundColor, |
|||
child: new ClipRect( |
|||
child: new _AllSectionsView( |
|||
sectionIndex: index, |
|||
sections: AnimationSectionsUtils.allSections, |
|||
selectedIndex: this.selectedIndex, |
|||
minHeight: AnimationHomeUtils._kAppBarMinHeight, |
|||
midHeight: AnimationHomeUtils._kAppBarMidHeight, |
|||
maxHeight: maxHeight, |
|||
sectionCards: sectionCards |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
return headings; |
|||
} |
|||
|
|||
Widget _buildBody(BuildContext context) { |
|||
MediaQueryData mediaQueryData = MediaQuery.of(context); |
|||
float statusBarHeight = mediaQueryData.padding.top; |
|||
float screenHeight = mediaQueryData.size.height; |
|||
float appBarMaxHeight = screenHeight - statusBarHeight; |
|||
|
|||
float appBarMidScrollOffset = statusBarHeight + appBarMaxHeight - AnimationHomeUtils._kAppBarMidHeight; |
|||
|
|||
return SizedBox.expand( |
|||
child: new NotificationListener<ScrollNotification>( |
|||
onNotification: (ScrollNotification notification) => { |
|||
return this._handleScrollNotification(notification, appBarMidScrollOffset); |
|||
}, |
|||
child: new CustomScrollView( |
|||
controller: this._scrollController, |
|||
physics: new _SnappingScrollPhysics(midScrollOffset: appBarMidScrollOffset), |
|||
slivers: new List<Widget> { |
|||
new _StatusBarPaddingSliver( |
|||
maxHeight: statusBarHeight, |
|||
scrollFactor: 7.0f |
|||
), |
|||
new SliverPersistentHeader( |
|||
pinned: true, |
|||
del: new _SliverAppBarDelegate( |
|||
minHeight: AnimationHomeUtils._kAppBarMinHeight, |
|||
maxHeight: appBarMaxHeight, |
|||
child: new NotificationListener<ScrollNotification>( |
|||
onNotification: (ScrollNotification notification) => { |
|||
return this._handlePageNotification(notification, |
|||
this._headingPageController, this._detailsPageController); |
|||
}, |
|||
child: new PageView( |
|||
physics: this._headingScrollPhysics, |
|||
controller: this._headingPageController, |
|||
children: this._allHeadingItems(appBarMaxHeight, |
|||
appBarMidScrollOffset) |
|||
) |
|||
) |
|||
) |
|||
), |
|||
new SliverToBoxAdapter( |
|||
child: new SizedBox( |
|||
height: 300.0f, |
|||
child: new NotificationListener<ScrollNotification>( |
|||
onNotification: (ScrollNotification notification) => |
|||
{ |
|||
return false; |
|||
//return this._handlePageNotification(notification,
|
|||
// this._detailsPageController, this._headingPageController);
|
|||
}, |
|||
child: new PageView( |
|||
controller: this._detailsPageController, |
|||
physics: new NeverScrollableScrollPhysics(), |
|||
children: AnimationSectionsUtils.allSections |
|||
.Select<Section, Widget>((Section section) => { |
|||
/*return new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: this._detailItemsFor(section).ToList() |
|||
);*/ |
|||
return new Container(color: Color.lerp(section.leftColor, section.rightColor, 0.5f).withAlpha(127), |
|||
child: new SectionDetailView(detail: section) |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
|
|||
|
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c714185ddbbb4ee4a0cf2a86cf3c6f2b |
|||
timeCreated: 1626763082 |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.gallery |
|||
{ |
|||
public class Photo : StatelessWidget |
|||
{ |
|||
public Photo(Key key = null, string photo = null, Action onTap = null) : base(key: key) |
|||
{ |
|||
D.assert(photo != null); |
|||
this.photo = photo; |
|||
this.onTap = onTap; |
|||
} |
|||
|
|||
public readonly string photo; |
|||
public readonly Action onTap; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new GestureDetector( |
|||
onTap: () => onTap?.Invoke(), |
|||
child: new LayoutBuilder( |
|||
builder: ((buildContext, constraints) => |
|||
{ |
|||
return Image.file(photo, fit: BoxFit.contain); |
|||
}) ) |
|||
); |
|||
|
|||
} |
|||
} |
|||
|
|||
public class RadialExpansion : StatelessWidget |
|||
{ |
|||
public RadialExpansion(Key key = null, float maxRadius = 0.0f, Widget child = null) |
|||
: base(key: key) |
|||
{ |
|||
this.maxRadius = maxRadius; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly float maxRadius; |
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new ClipOval( |
|||
child: new Center( |
|||
child: new SizedBox( |
|||
width: 2.0f * (maxRadius / Mathf.Sqrt(2)), |
|||
height: 2.0f * (maxRadius / Mathf.Sqrt(2)), |
|||
child: new ClipRect( |
|||
child: child |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 48950e92c7e041f7baf9e56498da6643 |
|||
timeCreated: 1626763082 |
|
|||
using System.Collections.Generic; |
|||
using uiwidgets; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
public class AnimationSectionsUtils { |
|||
public static readonly Color _mariner = new Color(0xFF3B5F8F); |
|||
public static readonly Color _mediumPurple = new Color(0xFF8266D4); |
|||
public static readonly Color _tomato = new Color(0xFFF95B57); |
|||
public static readonly Color _mySin = new Color(0xFFF3A646); |
|||
const string _kGalleryAssetsPackage = "flutter_gallery_assets"; |
|||
|
|||
public static readonly SectionDetail _eyeglassesDetail = new SectionDetail( |
|||
imageAsset: "heroSample/cube2.jpeg", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
title: "A cube is a three-dimensional solid object bounded by six square faces, facets or sides, with three meeting at each vertex", |
|||
subtitle: "3K views - 5 days" |
|||
); |
|||
|
|||
public static readonly SectionDetail _seatingDetail = new SectionDetail( |
|||
imageAsset: "heroSample/sphere2.jpeg", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
title: "A sphere is a geometrical object in three-dimensional space that is the surface of a ball", |
|||
subtitle: "3K views - 5 days" |
|||
); |
|||
|
|||
public static readonly SectionDetail _decorationDetail = new SectionDetail( |
|||
imageAsset: "heroSample/capture2.jpeg", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
title: "A capsule is a basic three-dimensional geometric shape consisting of a cylinder with hemispherical ends", |
|||
subtitle: "3K views - 5 days" |
|||
); |
|||
|
|||
public static readonly SectionDetail _protectionDetail = new SectionDetail( |
|||
imageAsset: "heroSample/cylinder2.jpeg", |
|||
imageAssetPackage: _kGalleryAssetsPackage, |
|||
title: "A cylindrical surface is a surface consisting of all the points on all the lines which are parallel to a given line", |
|||
subtitle: "3K views - 5 days" |
|||
); |
|||
|
|||
public static List<Section> allSections = new List<Section> { |
|||
new Section( |
|||
heroType: 0, |
|||
title: "CUBE", |
|||
leftColor: _mediumPurple, |
|||
rightColor: _mariner, |
|||
backgroundAsset: "products/sunnies", |
|||
backgroundAssetPackage: _kGalleryAssetsPackage, |
|||
details: new List<SectionDetail> { |
|||
_eyeglassesDetail |
|||
} |
|||
), |
|||
new Section( |
|||
heroType: 1, |
|||
title: "SPHERE", |
|||
leftColor: _tomato, |
|||
rightColor: _mediumPurple, |
|||
backgroundAsset: "products/table", |
|||
backgroundAssetPackage: _kGalleryAssetsPackage, |
|||
details: new List<SectionDetail> { |
|||
_seatingDetail |
|||
} |
|||
), |
|||
new Section( |
|||
heroType: 2, |
|||
title: "CAPSULE", |
|||
leftColor: _mySin, |
|||
rightColor: _tomato, |
|||
backgroundAsset: "products/earrings", |
|||
backgroundAssetPackage: _kGalleryAssetsPackage, |
|||
details: new List<SectionDetail> { |
|||
_decorationDetail |
|||
} |
|||
), |
|||
new Section( |
|||
heroType: 3, |
|||
title: "CYLINDER", |
|||
leftColor: Colors.green, |
|||
rightColor: Colors.lightGreen, |
|||
backgroundAsset: "products/hat", |
|||
backgroundAssetPackage: _kGalleryAssetsPackage, |
|||
details: new List<SectionDetail> { |
|||
_protectionDetail |
|||
} |
|||
) |
|||
}; |
|||
} |
|||
|
|||
|
|||
public class SectionDetail { |
|||
public SectionDetail( |
|||
string title = null, |
|||
string subtitle = null, |
|||
string imageAsset = null, |
|||
string imageAssetPackage = null |
|||
) { |
|||
this.title = title; |
|||
this.subtitle = subtitle; |
|||
this.imageAsset = imageAsset; |
|||
this.imageAssetPackage = imageAssetPackage; |
|||
} |
|||
|
|||
public readonly string title; |
|||
public readonly string subtitle; |
|||
public readonly string imageAsset; |
|||
public readonly string imageAssetPackage; |
|||
} |
|||
|
|||
public class Section { |
|||
public Section( |
|||
int heroType, |
|||
string title, |
|||
string backgroundAsset, |
|||
string backgroundAssetPackage, |
|||
Color leftColor, |
|||
Color rightColor, |
|||
List<SectionDetail> details |
|||
) |
|||
{ |
|||
this.heroType = heroType; |
|||
this.title = title; |
|||
this.backgroundAsset = backgroundAsset; |
|||
this.backgroundAssetPackage = backgroundAssetPackage; |
|||
this.leftColor = leftColor; |
|||
this.rightColor = rightColor; |
|||
this.details = details; |
|||
} |
|||
|
|||
public readonly string title; |
|||
public readonly string backgroundAsset; |
|||
public readonly string backgroundAssetPackage; |
|||
public readonly Color leftColor; |
|||
public readonly Color rightColor; |
|||
public readonly List<SectionDetail> details; |
|||
public readonly int heroType; |
|||
|
|||
public static bool operator ==(Section left, Section right) { |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(Section left, Section right) { |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
public bool Equals(Section other) { |
|||
return this.title == other.title; |
|||
} |
|||
|
|||
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((Section) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
return this.title.GetHashCode(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f722a96481a94642907ef6a5193f64b4 |
|||
timeCreated: 1626763082 |
|
|||
using System.Collections.Generic; |
|||
using uiwidgets; |
|||
using Unity.UIWidgets.animation; |
|||
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 UnityEngine; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using Image = Unity.UIWidgets.widgets.Image; |
|||
using Rect = Unity.UIWidgets.ui.Rect; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
using Transform = Unity.UIWidgets.widgets.Transform; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class AnimationWidgetsUtils { |
|||
public const float kSectionIndicatorWidth = 32.0f; |
|||
} |
|||
|
|||
public class SectionCard : StatelessWidget { |
|||
public SectionCard( |
|||
Key key = null, |
|||
Section section = null |
|||
) : base(key: key) { |
|||
D.assert(section != null); |
|||
this.section = section; |
|||
} |
|||
|
|||
public readonly Section section; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new DecoratedBox( |
|||
decoration: new BoxDecoration( |
|||
gradient: new LinearGradient( |
|||
begin: Alignment.centerLeft, |
|||
end: Alignment.centerRight, |
|||
colors: new List<Color> { |
|||
this.section.leftColor, this.section.rightColor |
|||
} |
|||
) |
|||
), |
|||
/*child: Image.asset(this.section.backgroundAsset, |
|||
color: Color.fromRGBO(255, 255, 255, 0.075f), |
|||
colorBlendMode: BlendMode.modulate, |
|||
fit: BoxFit.cover |
|||
)*/ |
|||
child: new Container() |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class SectionTitle : StatelessWidget { |
|||
public SectionTitle( |
|||
Key key = null, |
|||
Section section = null, |
|||
float? scale = null, |
|||
float? opacity = null |
|||
) : base(key: key) { |
|||
D.assert(section != null); |
|||
D.assert(scale != null); |
|||
D.assert(opacity != null && opacity >= 0.0f && opacity <= 1.0f); |
|||
this.section = section; |
|||
this.scale = scale; |
|||
this.opacity = opacity; |
|||
} |
|||
|
|||
public readonly Section section; |
|||
public readonly float? scale; |
|||
public readonly float? opacity; |
|||
|
|||
public static readonly TextStyle sectionTitleStyle = new TextStyle( |
|||
fontFamily: "Raleway", |
|||
inherit: false, |
|||
fontSize: 24.0f, |
|||
fontWeight: FontWeight.w500, |
|||
color: Colors.white, |
|||
textBaseline: TextBaseline.alphabetic |
|||
); |
|||
|
|||
public static readonly TextStyle sectionTitleShadowStyle = sectionTitleStyle.copyWith( |
|||
color: new Color(0x19000000) |
|||
); |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
var scale = this.scale ?? 1.0f; |
|||
return new IgnorePointer( |
|||
child: new Opacity( |
|||
opacity: this.opacity ?? 1.0f, |
|||
child: new Transform( |
|||
transform: Matrix4.diagonal3(new Vector3(scale, scale, scale)), |
|||
alignment: Alignment.center, |
|||
child: new Stack( |
|||
children: new List<Widget> { |
|||
new Positioned( |
|||
top: 4.0f, |
|||
child: new Text(this.section.title, style: sectionTitleShadowStyle) |
|||
), |
|||
new Text(this.section.title, style: sectionTitleStyle) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class SectionIndicator : StatelessWidget { |
|||
public SectionIndicator(Key key = null, float opacity = 1.0f) : base(key: key) { |
|||
this.opacity = opacity; |
|||
} |
|||
|
|||
public readonly float opacity; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new IgnorePointer( |
|||
child: new Container( |
|||
width: AnimationWidgetsUtils.kSectionIndicatorWidth, |
|||
height: 3.0f, |
|||
color: Colors.white.withOpacity(this.opacity) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class SectionDetailView : StatelessWidget { |
|||
public SectionDetailView( |
|||
Key key = null, |
|||
Section detail = null |
|||
) : base(key: key) { |
|||
this.detail = detail; |
|||
} |
|||
|
|||
public readonly Section detail; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Column( |
|||
|
|||
children: new List<Widget> |
|||
{ |
|||
new Padding(padding: EdgeInsets.only(top: 50f)), |
|||
_buildHero(context, detail.details[0].imageAsset, detail), |
|||
new Padding( |
|||
padding: EdgeInsets.symmetric(vertical: 15f, horizontal: 20f), |
|||
child: new Text(data: detail.details[0].title, style: new TextStyle(color: Color.white))) |
|||
}); |
|||
} |
|||
|
|||
const float kMinRadius = 64.0f; |
|||
const float kMaxRadius = 96.0f; |
|||
static Interval opacityCurve = new Interval(0.0f, 0.75f, curve: Curves.fastOutSlowIn); |
|||
|
|||
static RectTween _createRectTween(Rect begin, Rect end) { |
|||
return new MaterialRectCenterArcTween(begin: begin, end: end); |
|||
} |
|||
|
|||
static Widget _buildPage(BuildContext context, string imageName, Section description) |
|||
{ |
|||
return new Container( |
|||
color: description.leftColor, |
|||
child: new Center( |
|||
child: new Card( |
|||
elevation: 8.0f, |
|||
color: description.rightColor, |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>() { |
|||
new SizedBox( |
|||
width: kMaxRadius * 2.0f, |
|||
height: kMaxRadius * 2.0f, |
|||
child: new Hero( |
|||
createRectTween: _createRectTween, |
|||
tag: imageName, |
|||
child: new RadialExpansion( |
|||
maxRadius: kMaxRadius, |
|||
child: new Photo( |
|||
photo: imageName, |
|||
onTap: () => |
|||
{ |
|||
Navigator.of(context).pop<object>(); |
|||
} |
|||
|
|||
) |
|||
) |
|||
) |
|||
), |
|||
new OutlineButton( |
|||
onPressed: () => |
|||
{ |
|||
heroItem.heroType = description.heroType; |
|||
Navigator.of(context).pop<object>(); |
|||
}, |
|||
borderSide:new BorderSide(color: Colors.white), |
|||
highlightedBorderColor: Colors.transparent, |
|||
child: new Text( |
|||
"Choose", |
|||
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.white), |
|||
textScaleFactor: 1.5f |
|||
)), |
|||
new SizedBox(height: 16.0f) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildHero(BuildContext context, string imageName, Section description) { |
|||
return new Container( |
|||
width: kMinRadius * 2.0f, |
|||
height: kMinRadius * 2.0f, |
|||
child: new Hero( |
|||
createRectTween: _createRectTween, |
|||
tag: imageName, |
|||
child: new RadialExpansion( |
|||
maxRadius: kMaxRadius, |
|||
child: new Photo( |
|||
photo: imageName, |
|||
onTap: () => { |
|||
Navigator.of(context).push( |
|||
new PageRouteBuilder( |
|||
pageBuilder: (BuildContext subContext, Animation<float> animation, Animation<float> secondaryAnimation) => { |
|||
return new AnimatedBuilder( |
|||
animation: animation, |
|||
builder: (BuildContext subSubContext, Widget child) => { |
|||
return new Opacity( |
|||
opacity: opacityCurve.transform(animation.value), |
|||
child: _buildPage(context, imageName, description) |
|||
); |
|||
} |
|||
); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0d99121ed7e34f648b3047eab5417c11 |
|||
timeCreated: 1626763083 |
|
|||
fileFormatVersion: 2 |
|||
guid: 94e718fb1fbb444e99d49a448fc2e3c8 |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 17838ba8f271042dcb26a8e6c3a4c278 |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 8cfbfb0f75de2497ba3143c4e0ca94df |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: d82776d6188ac4524a96b7d63849c05f |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue