xingwei.zhu
6 年前
当前提交
204b4bc8
共有 21 个文件被更改,包括 2170 次插入 和 10 次删除
-
289Runtime/material/app_bar.cs
-
19Runtime/material/back_button.cs
-
21Runtime/rendering/layer.cs
-
51Runtime/rendering/proxy_box.cs
-
14Runtime/widgets/perferred_size.cs
-
31Runtime/widgets/transitions.cs
-
11Runtime/material/app_bar.cs.meta
-
11Runtime/material/back_button.cs.meta
-
11Runtime/material/bottom_app_bar.cs.meta
-
213Runtime/material/flexible_space_bar.cs
-
11Runtime/material/flexible_space_bar.cs.meta
-
277Runtime/material/float_action_button.cs
-
11Runtime/material/float_action_button.cs.meta
-
221Runtime/material/float_action_button_location.cs
-
11Runtime/material/float_action_button_location.cs.meta
-
752Runtime/material/scaffold.cs
-
11Runtime/material/scaffold.cs.meta
-
161Runtime/material/snack_bar.cs
-
32Runtime/widgets/annotated_region.cs
-
11Runtime/widgets/annotated_region.cs.meta
-
11Runtime/widgets/perferred_size.cs.meta
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
public class app_bar { |
|||
static class AppBarUtils { |
|||
internal const float _kLeadingWidth = Constants.kToolbarHeight; |
|||
} |
|||
|
|||
class _ToolbarContainerLayout : SingleChildLayoutDelegate { |
|||
public _ToolbarContainerLayout() {} |
|||
|
|||
public override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { |
|||
return constraints.tighten(height: Constants.kToolbarHeight); |
|||
} |
|||
|
|||
public override Size getSize(BoxConstraints constraints) { |
|||
return new Size(constraints.maxWidth, Constants.kToolbarHeight); |
|||
} |
|||
|
|||
public override Offset getPositionForChild(Size size, Size childSize) { |
|||
return new Offset(0.0f, size.height - childSize.height); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
class AppBar : StatefulWidget, IPreferredSizeWidget { |
|||
public AppBar( |
|||
Key key = null, |
|||
Widget leading = null, |
|||
bool automaticallyImplyLeading = true, |
|||
Widget title = null, |
|||
List<Widget> actions = null, |
|||
Widget flexibleSpace = null, |
|||
PreferredSizeWidget bottom = null, |
|||
float elevation = 4.0f, |
|||
Color backgroundColor = null, |
|||
Brightness? brightness = null, |
|||
IconThemeData iconTheme = null, |
|||
TextTheme textTheme = null, |
|||
bool primary = true, |
|||
bool? centerTitle = null, |
|||
float titleSpacing = NavigationToolbar.kMiddleSpacing, |
|||
float toolbarOpacity = 1.0f, |
|||
float bottomOpacity = 1.0f) : base(key: key) { |
|||
this.leading = leading; |
|||
this.automaticallyImplyLeading = automaticallyImplyLeading; |
|||
this.title = title; |
|||
this.actions = actions; |
|||
this.flexibleSpace = flexibleSpace; |
|||
this.bottom = bottom; |
|||
this.elevation = elevation; |
|||
this.backgroundColor = backgroundColor; |
|||
this.brightness = brightness; |
|||
this.iconTheme = iconTheme; |
|||
this.textTheme = textTheme; |
|||
this.primary = primary; |
|||
this.centerTitle = centerTitle; |
|||
this.titleSpacing = titleSpacing; |
|||
this.toolbarOpacity = toolbarOpacity; |
|||
this.bottomOpacity = bottomOpacity; |
|||
this.preferredSize = Size.fromHeight(Constants.kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0f)); |
|||
} |
|||
|
|||
public readonly Widget leading; |
|||
|
|||
public readonly bool automaticallyImplyLeading; |
|||
|
|||
public readonly Widget title; |
|||
|
|||
public readonly List<Widget> actions; |
|||
|
|||
public readonly Widget flexibleSpace; |
|||
|
|||
public readonly PreferredSizeWidget bottom; |
|||
|
|||
public readonly float elevation; |
|||
|
|||
public readonly Color backgroundColor; |
|||
|
|||
public readonly Brightness? brightness; |
|||
|
|||
public readonly IconThemeData iconTheme; |
|||
|
|||
public readonly TextTheme textTheme; |
|||
|
|||
public readonly bool primary; |
|||
|
|||
public readonly bool? centerTitle; |
|||
|
|||
public readonly float titleSpacing; |
|||
|
|||
public readonly float toolbarOpacity; |
|||
|
|||
public readonly float bottomOpacity; |
|||
public Size preferredSize { get; } |
|||
|
|||
public bool? _getEffectiveCenterTitle(ThemeData themeData) { |
|||
if (this.centerTitle != null) { |
|||
return this.centerTitle; |
|||
} |
|||
D.assert(themeData.platform != null); |
|||
switch (themeData.platform) { |
|||
case RuntimePlatform.IPhonePlayer: |
|||
return this.actions == null || this.actions.Count < 2; |
|||
default: |
|||
return false; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _AppBarState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _AppBarState : State<AppBar> { |
|||
void _handleDrawerButton() { |
|||
Scaffold.of(this.context).openDrawer(); |
|||
} |
|||
|
|||
void _handleDrawerButtonEnd() { |
|||
Scaffold.of(this.context).openEndDrawer(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(!this.widget.primary); |
|||
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context)); |
|||
ThemeData themeData = Theme.of(context); |
|||
ScaffoldState scaffold = Scaffold.of(context, nullOk: true); |
|||
ModalRoute parentRoute = ModalRoute.of(context); |
|||
|
|||
bool hasDrawer = scaffold?.hasDrawer ?? false; |
|||
bool hasEndDrawer = scaffold?.hasEndDrawer ?? false; |
|||
bool canPop = parentRoute?.canPop ?? false; |
|||
bool useCloseButton = parentRoute is PageRoute && ((PageRoute) parentRoute).fullscreenDialog; |
|||
|
|||
IconThemeData appBarIconTheme = this.widget.iconTheme ?? themeData.primaryIconTheme; |
|||
TextStyle centerStyle = this.widget.textTheme?.title ?? themeData.primaryTextTheme.title; |
|||
TextStyle sideStyle = this.widget.textTheme?.body1 ?? themeData.primaryTextTheme.body1; |
|||
|
|||
if (this.widget.toolbarOpacity != 1.0f) { |
|||
float opacity = new Interval(0.25f, 1.0f, curve: Curves.fastOutSlowIn).transform(this.widget.toolbarOpacity); |
|||
if (centerStyle?.color != null) |
|||
centerStyle = centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity)); |
|||
if (sideStyle?.color != null) |
|||
sideStyle = sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity)); |
|||
appBarIconTheme = appBarIconTheme.copyWith( |
|||
opacity: opacity * (appBarIconTheme.opacity ?? 1.0f) |
|||
); |
|||
} |
|||
|
|||
Widget leading = this.widget.leading; |
|||
if (leading == null && this.widget.automaticallyImplyLeading) { |
|||
if (hasDrawer) { |
|||
leading = new IconButton( |
|||
icon: new Icon(Icons.menu), |
|||
onPressed: this._handleDrawerButton, |
|||
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip); |
|||
} |
|||
else { |
|||
if (canPop) { |
|||
leading = useCloseButton ? (Widget)new CloseButton() : new BackButton() : |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (leading != null) { |
|||
leading = new ConstrainedBox( |
|||
constraints: BoxConstraints.tightFor(width: AppBarUtils._kLeadingWidth), |
|||
child: leading); |
|||
} |
|||
|
|||
Widget title = this.widget.title; |
|||
if (title != null) { |
|||
bool namesRoute = false; |
|||
switch (Application.platform) { |
|||
case RuntimePlatform.IPhonePlayer: |
|||
break; |
|||
default: |
|||
namesRoute = true; |
|||
break; |
|||
} |
|||
title = new DefaultTextStyle( |
|||
style: centerStyle, |
|||
softWrap: false, |
|||
overflow: TextOverflow.ellipsis, |
|||
child: title); |
|||
} |
|||
|
|||
Widget actions = null; |
|||
if (this.widget.actions != null && this.widget.actions.isNotEmpty()) { |
|||
actions = new Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: this.widget.actions); |
|||
} else if (hasEndDrawer) { |
|||
actions = new IconButton( |
|||
icon: new Icon(Icons.menu), |
|||
onPressed: this._handleDrawerButtonEnd, |
|||
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip); |
|||
} |
|||
|
|||
Widget toolbar = new NavigationToolbar( |
|||
leading: leading, |
|||
middle: title, |
|||
trailing: actions, |
|||
centerMiddle: this.widget._getEffectiveCenterTitle(themeData).Value, |
|||
middleSpacing: this.widget.titleSpacing); |
|||
|
|||
Widget appBar = new ClipRect( |
|||
child: new CustomSingleChildLayout( |
|||
layoutDelegate: new _ToolbarContainerLayout(), |
|||
child: IconTheme.merge( |
|||
data: appBarIconTheme, |
|||
child: new DefaultTextStyle( |
|||
style: sideStyle, |
|||
child: toolbar) |
|||
) |
|||
) |
|||
); |
|||
|
|||
if (this.widget.bottom != null) { |
|||
appBar = new Column( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: new List<Widget> { |
|||
new Flexible( |
|||
child: new ConstrainedBox( |
|||
constraints: new BoxConstraints(maxHeight: Constants.kToolbarHeight), |
|||
child: appBar |
|||
) |
|||
), |
|||
this.widget.bottomOpacity == 1.0f |
|||
? (Widget) this.widget.bottom |
|||
: new Opacity( |
|||
opacity: new Interval(0.25f, 1.0f, curve: Curves.fastOutSlowIn).transform(this.widget |
|||
.bottomOpacity), |
|||
child: this.widget.bottom |
|||
) |
|||
} |
|||
); |
|||
} |
|||
|
|||
if (this.widget.primary) { |
|||
appBar = new SafeArea( |
|||
top: true, |
|||
child: appBar); |
|||
} |
|||
|
|||
appBar = new Align( |
|||
alignment: Alignment.topCenter, |
|||
child: appBar); |
|||
|
|||
if (this.widget.flexibleSpace != null) { |
|||
appBar = new Stack( |
|||
fit: StackFit.passthrough, |
|||
children: new List<Widget> { |
|||
this.widget.flexibleSpace, |
|||
appBar |
|||
} |
|||
); |
|||
} |
|||
|
|||
Brightness brightness = this.widget.brightness ?? themeData.primaryColorBrightness; |
|||
SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark |
|||
? SystemUiOverlayStyle.light |
|||
: SystemUiOverlayStyle.dark; |
|||
|
|||
return new AnnotatedRegion<SystemUiOverlayStyle>( |
|||
value: overlayStyle, |
|||
child: new Material( |
|||
color: this.widget.backgroundColor ?? themeData.primaryColor, |
|||
elevation: this.widget.elevation, |
|||
child: appBar |
|||
)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: da897030c4af84749a3ac5494e45c359 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 485e2aa6981384670925d74e140d54b4 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: e86f2ad5f24fd47cf9154c2b99ab5abb |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
using Transform = Unity.UIWidgets.widgets.Transform; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public enum CollapseMode { |
|||
parallax, |
|||
pin, |
|||
none |
|||
} |
|||
|
|||
public class FlexibleSpaceBar : StatefulWidget { |
|||
public FlexibleSpaceBar( |
|||
Key key = null, |
|||
Widget title = null, |
|||
Widget background = null, |
|||
bool? centerTitle = null, |
|||
CollapseMode collapseMode = CollapseMode.parallax |
|||
) : base(key: key) { |
|||
this.title = title; |
|||
this.background = background; |
|||
this.centerTitle = centerTitle; |
|||
this.collapseMode = collapseMode; |
|||
} |
|||
|
|||
public readonly Widget title; |
|||
|
|||
public readonly Widget background; |
|||
|
|||
public readonly bool? centerTitle; |
|||
|
|||
public readonly CollapseMode collapseMode; |
|||
|
|||
public static Widget createSettings( |
|||
float? toolbarOpacity = null, |
|||
float? minExtent = null, |
|||
float? maxExtent = null, |
|||
float? currentExtent = null, |
|||
Widget child = null) { |
|||
D.assert(currentExtent != null); |
|||
D.assert(child != null); |
|||
return new FlexibleSpaceBarSettings( |
|||
toolbarOpacity: toolbarOpacity ?? 1.0f, |
|||
minExtent: minExtent ?? currentExtent, |
|||
maxExtent: maxExtent ?? currentExtent, |
|||
currentExtent: currentExtent, |
|||
child: child |
|||
); |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _FlexibleSpaceBarState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _FlexibleSpaceBarState : State<FlexibleSpaceBar> { |
|||
bool? _getEffectiveCenterTitle(ThemeData themeData) { |
|||
if (this.widget.centerTitle != null) { |
|||
return this.widget.centerTitle; |
|||
} |
|||
D.assert(themeData.platform != null); |
|||
switch (themeData.platform) { |
|||
case RuntimePlatform.IPhonePlayer: |
|||
return true; |
|||
default: |
|||
return false; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
Alignment _getTitleAlignment(bool effectiveCenterTitle) { |
|||
if (effectiveCenterTitle) { |
|||
return Alignment.bottomCenter; |
|||
} |
|||
|
|||
return Alignment.bottomLeft; |
|||
} |
|||
|
|||
float? _getCollapsePadding(float t, FlexibleSpaceBarSettings settings) { |
|||
switch (this.widget.collapseMode) { |
|||
case CollapseMode.pin: |
|||
return -(settings.maxExtent.Value - settings.currentExtent.Value); |
|||
case CollapseMode.parallax: |
|||
float deltaExtent = settings.maxExtent.Value - settings.minExtent.Value; |
|||
return -new FloatTween(begin: 0.0f, end: deltaExtent / 4.0f).lerp(t); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
FlexibleSpaceBarSettings settings = (FlexibleSpaceBarSettings)context.inheritFromWidgetOfExactType(typeof(FlexibleSpaceBarSettings)); |
|||
D.assert(settings != null, "A FlexibleSpaceBar must be wrapped in the widget returned by FlexibleSpaceBar.createSettings()."); |
|||
|
|||
List<Widget> children = new List<Widget>(); |
|||
float deltaExtent = settings.maxExtent.Value - settings.minExtent.Value; |
|||
|
|||
float t = (1.0f - (settings.currentExtent.Value - settings.minExtent.Value) / deltaExtent.clamp(0.0f, 1.0f)); |
|||
|
|||
if (this.widget.background != null) { |
|||
float fadeStart = Mathf.Max(0.0f, 1.0f - Constants.kToolbarHeight / deltaExtent); |
|||
float fadeEnd = 1.0f; |
|||
D.assert(fadeStart <= fadeEnd); |
|||
|
|||
float opacity = 1.0f - new Interval(fadeStart, fadeEnd).transform(t); |
|||
if (opacity > 0.0f) { |
|||
children.Add(new Positioned( |
|||
top: this._getCollapsePadding(t, settings), |
|||
left: 0.0f, |
|||
right: 0.0f, |
|||
height: settings.maxExtent, |
|||
child: new Opacity( |
|||
opacity: opacity, |
|||
child: this.widget.background) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
Widget title = null; |
|||
if (this.widget.title != null) { |
|||
switch (Application.platform) { |
|||
case RuntimePlatform.IPhonePlayer: |
|||
title = this.widget.title; |
|||
break; |
|||
default: |
|||
title = this.widget.title; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
ThemeData theme = Theme.of(context); |
|||
float toolbarOpacity = settings.toolbarOpacity.Value; |
|||
if (toolbarOpacity > 0.0f) { |
|||
TextStyle titleStyle = theme.primaryTextTheme.title; |
|||
titleStyle = titleStyle.copyWith( |
|||
color: titleStyle.color.withOpacity(toolbarOpacity)); |
|||
bool effectiveCenterTitle = this._getEffectiveCenterTitle(theme).Value; |
|||
float scaleValue = new FloatTween(begin: 1.5f, end: 1.0f).lerp(t); |
|||
Matrix3 scaleTransform = Matrix3.makeScale(scaleValue, scaleValue); |
|||
Alignment titleAlignment = this._getTitleAlignment(effectiveCenterTitle); |
|||
children.Add(new Container( |
|||
padding: EdgeInsets.fromLTRB( |
|||
effectiveCenterTitle ? 0.0f : 72.0f, |
|||
0f, |
|||
0f, |
|||
16.0f), |
|||
child: new Transform( |
|||
alignment: titleAlignment, |
|||
transform: scaleTransform, |
|||
child: new Align( |
|||
alignment: titleAlignment, |
|||
child: new DefaultTextStyle( |
|||
style: titleStyle, |
|||
child: title) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
return new ClipRect( |
|||
child: new Stack( |
|||
children: children) |
|||
); |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
public class FlexibleSpaceBarSettings : InheritedWidget { |
|||
public FlexibleSpaceBarSettings( |
|||
Key key = null, |
|||
float? toolbarOpacity = null, |
|||
float? minExtent = null, |
|||
float? maxExtent = null, |
|||
float? currentExtent = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
D.assert(currentExtent != null); |
|||
this.toolbarOpacity = toolbarOpacity; |
|||
this.minExtent = minExtent; |
|||
this.maxExtent = maxExtent; |
|||
this.currentExtent = currentExtent; |
|||
} |
|||
|
|||
public readonly float? toolbarOpacity; |
|||
|
|||
public readonly float? minExtent; |
|||
|
|||
public readonly float? maxExtent; |
|||
|
|||
public readonly float? currentExtent; |
|||
|
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) { |
|||
FlexibleSpaceBarSettings _oldWidget = (FlexibleSpaceBarSettings) oldWidget; |
|||
return this.toolbarOpacity != _oldWidget.toolbarOpacity |
|||
|| this.minExtent != _oldWidget.minExtent |
|||
|| this.maxExtent != _oldWidget.maxExtent |
|||
|| this.currentExtent != _oldWidget.currentExtent; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ae1ab951014d2444da9ac1419a3f111b |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
static class FloatActionButtonUtils { |
|||
public static BoxConstraints _kSizeConstraints = BoxConstraints.tightFor(width: 56.0f, height: 56.0f); |
|||
|
|||
public static BoxConstraints _kMiniSizeConstraints = BoxConstraints.tightFor(width: 40.0f, height: 40.0f); |
|||
|
|||
public static BoxConstraints _kExtendedSizeConstraints = new BoxConstraints(minHeight: 48.0f, maxHeight: 48.0f); |
|||
} |
|||
|
|||
|
|||
class _DefaultHeroTag { |
|||
public _DefaultHeroTag() { |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "<default FloatingActionButton tag>"; |
|||
} |
|||
} |
|||
|
|||
public class FloatingActionButton : StatefulWidget { |
|||
protected FloatingActionButton( |
|||
Key key = null, |
|||
Widget child = null, |
|||
string tooltip = null, |
|||
Color foregroundColor = null, |
|||
Color backgroundColor = null, |
|||
object heroTag = null, |
|||
float elevation = 6.0f, |
|||
float highlightElevation = 12.0f, |
|||
VoidCallback onPressed = null, |
|||
bool mini = false, |
|||
ShapeBorder shape = null, |
|||
Clip clipBehavior = Clip.none, |
|||
MaterialTapTargetSize? materialTapTargetSize = null, |
|||
bool isExtended = false, |
|||
BoxConstraints _sizeConstraints = null |
|||
) : base(key: key) { |
|||
heroTag = heroTag ?? new _DefaultHeroTag(); |
|||
shape = shape ?? new CircleBorder(); |
|||
this.child = child; |
|||
this.tooltip = tooltip; |
|||
this.foregroundColor = foregroundColor; |
|||
this.backgroundColor = backgroundColor; |
|||
this.heroTag = heroTag; |
|||
this.elevation = elevation; |
|||
this.highlightElevation = highlightElevation; |
|||
this.onPressed = onPressed; |
|||
this.mini = mini; |
|||
this.shape = shape; |
|||
this.clipBehavior = clipBehavior; |
|||
this.materialTapTargetSize = materialTapTargetSize; |
|||
this.isExtended = isExtended; |
|||
this._sizeConstraints = _sizeConstraints ?? |
|||
(mini ? FloatActionButtonUtils._kMiniSizeConstraints : FloatActionButtonUtils._kSizeConstraints); |
|||
} |
|||
|
|||
public FloatingActionButton( |
|||
Key key = null, |
|||
Widget child = null, |
|||
string tooltip = null, |
|||
Color foregroundColor = null, |
|||
Color backgroundColor = null, |
|||
object heroTag = null, |
|||
float elevation = 6.0f, |
|||
float highlightElevation = 12.0f, |
|||
VoidCallback onPressed = null, |
|||
bool mini = false, |
|||
ShapeBorder shape = null, |
|||
Clip clipBehavior = Clip.none, |
|||
MaterialTapTargetSize? materialTapTargetSize = null, |
|||
bool isExtended = false |
|||
) : this(key : key, |
|||
child: child, |
|||
tooltip: tooltip, |
|||
foregroundColor: foregroundColor, |
|||
backgroundColor: backgroundColor, |
|||
heroTag: heroTag, |
|||
elevation: elevation, |
|||
highlightElevation: highlightElevation, |
|||
onPressed: onPressed, |
|||
mini: mini, |
|||
shape: shape, |
|||
clipBehavior: clipBehavior, |
|||
materialTapTargetSize: materialTapTargetSize, |
|||
isExtended: isExtended, |
|||
_sizeConstraints: null) { |
|||
} |
|||
|
|||
public static FloatingActionButton extended( |
|||
Key key = null, |
|||
string tooltip = null, |
|||
Color foregroundColor = null, |
|||
Color backgroundColor = null, |
|||
object heroTag = null, |
|||
float elevation = 6.0f, |
|||
float highlightElevation = 12.0f, |
|||
VoidCallback onPressed = null, |
|||
ShapeBorder shape = null, |
|||
bool isExtended = true, |
|||
MaterialTapTargetSize? materialTapTargetSize = null, |
|||
Clip clipBehavior = Clip.none, |
|||
Widget icon = null, |
|||
Widget label = null |
|||
) { |
|||
D.assert(icon != null); |
|||
D.assert(label != null); |
|||
heroTag = heroTag ?? new _DefaultHeroTag(); |
|||
shape = shape ?? new StadiumBorder(); |
|||
BoxConstraints _sizeConstraints = FloatActionButtonUtils._kExtendedSizeConstraints; |
|||
bool mini = false; |
|||
Widget child = new _ChildOverflowBox( |
|||
child: new Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget> { |
|||
new SizedBox(width: 16.0f), |
|||
icon, |
|||
new SizedBox(width: 8.0f), |
|||
label, |
|||
new SizedBox(width: 20.0f) |
|||
})); |
|||
|
|||
return new FloatingActionButton( |
|||
key: key, |
|||
child: child, |
|||
tooltip: tooltip, |
|||
foregroundColor: foregroundColor, |
|||
backgroundColor: backgroundColor, |
|||
heroTag: heroTag, |
|||
elevation: elevation, |
|||
highlightElevation: highlightElevation, |
|||
onPressed: onPressed, |
|||
mini: mini, |
|||
shape: shape, |
|||
clipBehavior: clipBehavior, |
|||
materialTapTargetSize: materialTapTargetSize, |
|||
isExtended: isExtended, |
|||
_sizeConstraints: _sizeConstraints |
|||
); |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly string tooltip; |
|||
|
|||
public readonly Color foregroundColor; |
|||
|
|||
public readonly Color backgroundColor; |
|||
|
|||
public readonly object heroTag; |
|||
|
|||
public readonly VoidCallback onPressed; |
|||
|
|||
public readonly float elevation; |
|||
|
|||
public readonly float highlightElevation; |
|||
|
|||
public readonly bool mini; |
|||
|
|||
public readonly ShapeBorder shape; |
|||
|
|||
public readonly Clip clipBehavior; |
|||
|
|||
public readonly bool isExtended; |
|||
|
|||
public readonly MaterialTapTargetSize? materialTapTargetSize; |
|||
|
|||
public readonly BoxConstraints _sizeConstraints; |
|||
|
|||
public override State createState() { |
|||
return new _FloatingActionButtonState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _FloatingActionButtonState : State<FloatingActionButton> { |
|||
bool _highlight = false; |
|||
|
|||
void _handleHighlightChanged(bool value) { |
|||
this.setState(() => { this._highlight = value; }); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
ThemeData theme = Theme.of(context); |
|||
Color foregroundColor = this.widget.foregroundColor ?? theme.accentIconTheme.color; |
|||
Widget result = null; |
|||
|
|||
if (this.widget.child != null) { |
|||
result = IconTheme.merge( |
|||
data: new IconThemeData( |
|||
color: foregroundColor), |
|||
child: this.widget.child |
|||
); |
|||
} |
|||
|
|||
result = new RawMaterialButton( |
|||
onPressed: this.widget.onPressed, |
|||
onHighlightChanged: this._handleHighlightChanged, |
|||
elevation: this._highlight ? this.widget.highlightElevation : this.widget.elevation, |
|||
constraints: this.widget._sizeConstraints, |
|||
materialTapTargetSize: this.widget.materialTapTargetSize ?? theme.materialTapTargetSize, |
|||
fillColor: this.widget.backgroundColor ?? theme.accentColor, |
|||
textStyle: theme.accentTextTheme.button.copyWith( |
|||
color: foregroundColor, |
|||
letterSpacing: 1.2f), |
|||
shape: this.widget.shape, |
|||
clipBehavior: this.widget.clipBehavior, |
|||
child: result); |
|||
|
|||
if (this.widget.tooltip != null) { |
|||
result = new Tooltip( |
|||
message: this.widget.tooltip, |
|||
child: result); |
|||
} |
|||
|
|||
//todo: xingwei.zhu: Hero widget
|
|||
// if (this.widget.heroTag != null) {
|
|||
// result = new Hero(
|
|||
// tag: this.widget.heroTag,
|
|||
// child: result);
|
|||
// }
|
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
class _ChildOverflowBox : SingleChildRenderObjectWidget { |
|||
public _ChildOverflowBox( |
|||
Key key = null, |
|||
Widget child = null) : base(key: key, child: child) { |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new _RenderChildOverflowBox(); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
class _RenderChildOverflowBox : RenderAligningShiftedBox { |
|||
public _RenderChildOverflowBox( |
|||
RenderBox child = null) : base(child: child, alignment: Alignment.center) {} |
|||
|
|||
protected override float computeMinIntrinsicWidth(float height) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
protected override float computeMinIntrinsicHeight(float width) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
if (this.child != null) { |
|||
this.child.layout(new BoxConstraints(), parentUsesSize: true); |
|||
this.size = new Size( |
|||
Mathf.Max(this.constraints.minWidth, Mathf.Min(this.constraints.maxWidth, this.child.size.width)), |
|||
Mathf.Max(this.constraints.minHeight, Mathf.Min(this.constraints.maxHeight, this.child.size.height)) |
|||
); |
|||
this.alignChild(); |
|||
} |
|||
else { |
|||
this.size = this.constraints.biggest; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 274f3c1005cd046a28b169d8048c0292 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public static class FloatingActionButtonLocationUtils { |
|||
public const float kFloatingActionButtonMargin = 16.0f; |
|||
|
|||
public static TimeSpan kFloatingActionButtonSegue = new TimeSpan(0, 0, 0, 0, 200); |
|||
|
|||
public const float kFloatingActionButtonTurnInterval = 0.125f; |
|||
} |
|||
|
|||
|
|||
public abstract class FloatingActionButtonLocation { |
|||
protected FloatingActionButtonLocation() { |
|||
} |
|||
|
|||
public static FloatingActionButtonLocation endFloat = new _EndFloatFabLocation(); |
|||
|
|||
public static FloatingActionButtonLocation centerFloat = new _CenterFloatFabLocation(); |
|||
|
|||
public static FloatingActionButtonLocation endDocked = new _EndDockedFloatingActionButtonLocation(); |
|||
|
|||
public static FloatingActionButtonLocation centerDocked = new _CenterDockedFloatingActionButtonLocation(); |
|||
|
|||
public abstract Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry); |
|||
|
|||
public override string ToString() { |
|||
return this.GetType().ToString(); |
|||
} |
|||
} |
|||
|
|||
class _CenterFloatFabLocation : FloatingActionButtonLocation { |
|||
public _CenterFloatFabLocation() { |
|||
} |
|||
|
|||
public override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
float fabX = (scaffoldGeometry.scaffoldSize.width - scaffoldGeometry.floatingActionButtonSize.width) / 2.0f; |
|||
|
|||
float contentBottom = scaffoldGeometry.contentBottom; |
|||
float bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height; |
|||
float fabHeight = scaffoldGeometry.floatingActionButtonSize.height; |
|||
float snackBarHeight = scaffoldGeometry.snackBarSize.height; |
|||
float fabY = contentBottom - fabHeight - FloatingActionButtonLocationUtils.kFloatingActionButtonMargin; |
|||
if (snackBarHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, |
|||
contentBottom - snackBarHeight - fabHeight - |
|||
FloatingActionButtonLocationUtils.kFloatingActionButtonMargin); |
|||
} |
|||
|
|||
if (bottomSheetHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, contentBottom - bottomSheetHeight - fabHeight / 2.0f); |
|||
} |
|||
|
|||
return new Offset(fabX, fabY); |
|||
} |
|||
} |
|||
|
|||
class _EndFloatFabLocation : FloatingActionButtonLocation { |
|||
public _EndFloatFabLocation() { |
|||
} |
|||
|
|||
public override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
float endPadding = scaffoldGeometry.minInsets.right; |
|||
float fabX = scaffoldGeometry.scaffoldSize.width - scaffoldGeometry.floatingActionButtonSize.width - |
|||
FloatingActionButtonLocationUtils.kFloatingActionButtonMargin - endPadding; |
|||
|
|||
float contentBottom = scaffoldGeometry.contentBottom; |
|||
float bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height; |
|||
float fabHeight = scaffoldGeometry.floatingActionButtonSize.height; |
|||
float snackBarHeight = scaffoldGeometry.snackBarSize.height; |
|||
|
|||
float fabY = contentBottom - fabHeight - FloatingActionButtonLocationUtils.kFloatingActionButtonMargin; |
|||
if (snackBarHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, |
|||
contentBottom - snackBarHeight - fabHeight - |
|||
FloatingActionButtonLocationUtils.kFloatingActionButtonMargin); |
|||
} |
|||
|
|||
if (bottomSheetHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, contentBottom - bottomSheetHeight - fabHeight / 2.0f); |
|||
} |
|||
|
|||
return new Offset(fabX, fabY); |
|||
} |
|||
} |
|||
|
|||
abstract class _DockedFloatingActionButtonLocation : FloatingActionButtonLocation { |
|||
protected _DockedFloatingActionButtonLocation() { |
|||
} |
|||
|
|||
protected float getDockedY(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
float contentBottom = scaffoldGeometry.contentBottom; |
|||
float bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height; |
|||
float fabHeight = scaffoldGeometry.floatingActionButtonSize.height; |
|||
float snackBarHeight = scaffoldGeometry.snackBarSize.height; |
|||
|
|||
float fabY = contentBottom - fabHeight / 2.0f; |
|||
if (snackBarHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, |
|||
contentBottom - snackBarHeight - fabHeight - |
|||
FloatingActionButtonLocationUtils.kFloatingActionButtonMargin); |
|||
} |
|||
|
|||
if (bottomSheetHeight > 0.0f) { |
|||
fabY = Mathf.Min(fabY, contentBottom - bottomSheetHeight - fabHeight / 2.0f); |
|||
} |
|||
|
|||
float maxFabY = scaffoldGeometry.scaffoldSize.height - fabHeight; |
|||
return Math.Min(maxFabY, fabY); |
|||
} |
|||
} |
|||
|
|||
class _EndDockedFloatingActionButtonLocation : _DockedFloatingActionButtonLocation { |
|||
public _EndDockedFloatingActionButtonLocation() { |
|||
} |
|||
|
|||
public override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
float endPadding = scaffoldGeometry.minInsets.right; |
|||
float fabX = scaffoldGeometry.scaffoldSize.width - scaffoldGeometry.floatingActionButtonSize.width - |
|||
FloatingActionButtonLocationUtils.kFloatingActionButtonMargin - endPadding; |
|||
return new Offset(fabX, this.getDockedY(scaffoldGeometry)); |
|||
} |
|||
} |
|||
|
|||
class _CenterDockedFloatingActionButtonLocation : _DockedFloatingActionButtonLocation { |
|||
public _CenterDockedFloatingActionButtonLocation() { |
|||
} |
|||
|
|||
public override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
float fabX = (scaffoldGeometry.scaffoldSize.width - scaffoldGeometry.floatingActionButtonSize.width) / 2.0f; |
|||
return new Offset(fabX, this.getDockedY(scaffoldGeometry)); |
|||
} |
|||
} |
|||
|
|||
public abstract class FloatingActionButtonAnimator { |
|||
protected FloatingActionButtonAnimator() { |
|||
} |
|||
|
|||
public static FloatingActionButtonAnimator scaling = new _ScalingFabMotionAnimator(); |
|||
|
|||
public abstract Offset getOffset(Offset begin, Offset end, float progress); |
|||
|
|||
public abstract Animation<float> getScaleAnimation(Animation<float> parent); |
|||
|
|||
public abstract Animation<float> getRotationAnimation(Animation<float> parent); |
|||
|
|||
public virtual float getAnimationRestart(float previousValue) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.GetType().ToString(); |
|||
} |
|||
} |
|||
|
|||
class _ScalingFabMotionAnimator : FloatingActionButtonAnimator { |
|||
public _ScalingFabMotionAnimator() { |
|||
} |
|||
|
|||
public override Offset getOffset(Offset begin, Offset end, float progress) { |
|||
if (progress < 0.5f) { |
|||
return begin; |
|||
} |
|||
else { |
|||
return end; |
|||
} |
|||
} |
|||
|
|||
public override Animation<float> getScaleAnimation(Animation<float> parent) { |
|||
Curve curve = new Interval(0.5f, 1.0f, curve: Curves.ease); |
|||
return new _AnimationSwap<float>( |
|||
new ReverseAnimation(parent.drive(new CurveTween(curve: curve.flipped))), |
|||
parent.drive(new CurveTween(curve: curve)), |
|||
parent, |
|||
0.5f |
|||
); |
|||
} |
|||
|
|||
static readonly Animatable<float> _rotationTween = new FloatTween( |
|||
begin: 1.0f - FloatingActionButtonLocationUtils.kFloatingActionButtonTurnInterval * 2.0f, |
|||
end: 1.0f |
|||
); |
|||
|
|||
static readonly Animatable<float> _thresholdCenterTween = new CurveTween(curve: new Threshold(0.5f)); |
|||
|
|||
public override Animation<float> getRotationAnimation(Animation<float> parent) { |
|||
return new _AnimationSwap<float>( |
|||
parent.drive(_rotationTween), |
|||
new ReverseAnimation(parent.drive(_thresholdCenterTween)), |
|||
parent, |
|||
0.5f |
|||
); |
|||
} |
|||
|
|||
public override float getAnimationRestart(float previousValue) { |
|||
return Mathf.Min(1.0f - previousValue, previousValue); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _AnimationSwap<T> : CompoundAnimation<T> { |
|||
public _AnimationSwap( |
|||
Animation<T> first, |
|||
Animation<T> next, |
|||
Animation<float> parent, |
|||
float swapThreshold) : base(first: first, next: next) { |
|||
this.parent = parent; |
|||
this.swapThreshold = swapThreshold; |
|||
} |
|||
|
|||
public readonly Animation<float> parent; |
|||
public readonly float swapThreshold; |
|||
|
|||
public override T value { |
|||
get { return this.parent.value < this.swapThreshold ? this.first.value : this.next.value; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: cfa1c894caa2a46b19d419f6f53ae91f |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
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 Rect = Unity.UIWidgets.ui.Rect; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
static class ScaffoldUtils { |
|||
public static FloatingActionButtonLocation _kDefaultFloatingActionButtonLocation = |
|||
FloatingActionButtonLocation.endFloat; |
|||
|
|||
public static FloatingActionButtonAnimator _kDefaultFloatingActionButtonAnimator = |
|||
FloatingActionButtonAnimator.scaling; |
|||
} |
|||
|
|||
public enum _ScaffoldSlot { |
|||
body, |
|||
appBar, |
|||
bottomSheet, |
|||
snackBar, |
|||
persistentFooter, |
|||
bottomNavigationBar, |
|||
floatingActionButton, |
|||
drawer, |
|||
endDrawer, |
|||
statusBar |
|||
} |
|||
|
|||
public class ScaffoldPrelayoutGeometry { |
|||
public ScaffoldPrelayoutGeometry( |
|||
Size bottomSheetSize = null, |
|||
float? contentBottom = null, |
|||
float? contentTop = null, |
|||
Size floatingActionButtonSize = null, |
|||
EdgeInsets minInsets = null, |
|||
Size scaffoldSize = null, |
|||
Size snackBarSize = null |
|||
) { |
|||
D.assert(bottomSheetSize != null); |
|||
D.assert(contentBottom != null); |
|||
D.assert(contentTop != null); |
|||
D.assert(floatingActionButtonSize != null); |
|||
D.assert(minInsets != null); |
|||
D.assert(scaffoldSize != null); |
|||
D.assert(snackBarSize != null); |
|||
|
|||
this.bottomSheetSize = bottomSheetSize; |
|||
this.contentBottom = contentBottom.Value; |
|||
this.contentTop = contentTop.Value; |
|||
this.floatingActionButtonSize = floatingActionButtonSize; |
|||
this.minInsets = minInsets; |
|||
this.scaffoldSize = scaffoldSize; |
|||
this.snackBarSize = snackBarSize; |
|||
} |
|||
|
|||
public readonly Size floatingActionButtonSize; |
|||
|
|||
public readonly Size bottomSheetSize; |
|||
|
|||
public readonly float contentBottom; |
|||
|
|||
public readonly float contentTop; |
|||
|
|||
public readonly EdgeInsets minInsets; |
|||
|
|||
public readonly Size scaffoldSize; |
|||
|
|||
public readonly Size snackBarSize; |
|||
} |
|||
|
|||
class _TransitionSnapshotFabLocation : FloatingActionButtonLocation { |
|||
public _TransitionSnapshotFabLocation( |
|||
FloatingActionButtonLocation begin, |
|||
FloatingActionButtonLocation end, |
|||
FloatingActionButtonAnimator animator, |
|||
float progress) { |
|||
this.begin = begin; |
|||
this.end = end; |
|||
this.animator = animator; |
|||
this.progress = progress; |
|||
} |
|||
|
|||
public readonly FloatingActionButtonLocation begin; |
|||
public readonly FloatingActionButtonLocation end; |
|||
public readonly FloatingActionButtonAnimator animator; |
|||
public readonly float progress; |
|||
|
|||
public override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { |
|||
return this.animator.getOffset( |
|||
begin: this.begin.getOffset(scaffoldGeometry), |
|||
end: this.end.getOffset(scaffoldGeometry), |
|||
progress: this.progress |
|||
); |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return this.GetType() + "(begin: " + this.begin + ", end: " + this.end + ", progress: " + this.progress; |
|||
} |
|||
} |
|||
|
|||
public class ScaffoldGeometry { |
|||
public ScaffoldGeometry( |
|||
float? bottomNavigationBarTop = null, |
|||
Rect floatingActionButtonArea = null) { |
|||
this.bottomNavigationBarTop = bottomNavigationBarTop; |
|||
this.floatingActionButtonArea = floatingActionButtonArea; |
|||
} |
|||
|
|||
public readonly float? bottomNavigationBarTop; |
|||
|
|||
public readonly Rect floatingActionButtonArea; |
|||
|
|||
public ScaffoldGeometry _scaleFloatingActionButton(float scaleFactor) { |
|||
if (scaleFactor == 1.0f) { |
|||
return this; |
|||
} |
|||
|
|||
if (scaleFactor == 0.0f) { |
|||
return new ScaffoldGeometry( |
|||
bottomNavigationBarTop: this.bottomNavigationBarTop); |
|||
} |
|||
|
|||
Rect scaledButton = Rect.lerp( |
|||
this.floatingActionButtonArea.center & Size.zero, |
|||
this.floatingActionButtonArea, |
|||
scaleFactor); |
|||
|
|||
return this.copyWith(floatingActionButtonArea: scaledButton); |
|||
} |
|||
|
|||
public ScaffoldGeometry copyWith( |
|||
float? bottomNavigationBarTop = null, |
|||
Rect floatingActionButtonArea = null |
|||
) { |
|||
return new ScaffoldGeometry( |
|||
bottomNavigationBarTop: bottomNavigationBarTop ?? this.bottomNavigationBarTop, |
|||
floatingActionButtonArea: floatingActionButtonArea ?? this.floatingActionButtonArea); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _ScaffoldGeometryNotifier : ValueNotifier<ScaffoldGeometry> { |
|||
public _ScaffoldGeometryNotifier( |
|||
ScaffoldGeometry geometry, BuildContext context) : base(geometry) { |
|||
D.assert(context != null); |
|||
this.context = context; |
|||
this.geometry = geometry; |
|||
} |
|||
|
|||
public readonly BuildContext context; |
|||
|
|||
float floatingActionButtonScale; |
|||
ScaffoldGeometry geometry; |
|||
|
|||
public new ScaffoldGeometry value { |
|||
get { |
|||
D.assert(() => { |
|||
RenderObject renderObject = this.context.findRenderObject(); |
|||
|
|||
if (renderObject == null || !renderObject.owner.debugDoingPaint) { |
|||
throw new UIWidgetsError( |
|||
"Scaffold.geometryOf() must only be accessed during the paint phase.\n" + |
|||
"The ScaffoldGeometry is only available during the paint phase, because\n" + |
|||
"its value is computed during the animation and layout phases prior to painting." |
|||
); |
|||
} |
|||
|
|||
return true; |
|||
}); |
|||
return this.geometry._scaleFloatingActionButton(this.floatingActionButtonScale); |
|||
} |
|||
} |
|||
|
|||
public void _updateWith( |
|||
float? bottomNavigationBarTop = null, |
|||
Rect floatingActionButtonArea = null, |
|||
float? floatingActionButtonScale = null |
|||
) { |
|||
this.floatingActionButtonScale = floatingActionButtonScale ?? this.floatingActionButtonScale; |
|||
this.geometry = this.geometry.copyWith( |
|||
bottomNavigationBarTop: bottomNavigationBarTop, |
|||
floatingActionButtonArea: floatingActionButtonArea); |
|||
this.notifyListeners(); |
|||
} |
|||
} |
|||
|
|||
class _ScaffoldLayout : MultiChildLayoutDelegate { |
|||
public _ScaffoldLayout( |
|||
EdgeInsets minInsets, |
|||
_ScaffoldGeometryNotifier geometryNotifier, |
|||
FloatingActionButtonLocation previousFloatingActionButtonLocation, |
|||
FloatingActionButtonLocation currentFloatingActionButtonLocation, |
|||
float floatingActionButtonMoveAnimationProgress, |
|||
FloatingActionButtonAnimator floatingActionButtonMotionAnimator |
|||
) { |
|||
D.assert(previousFloatingActionButtonLocation != null); |
|||
D.assert(currentFloatingActionButtonLocation != null); |
|||
|
|||
this.minInsets = minInsets; |
|||
this.geometryNotifier = geometryNotifier; |
|||
this.previousFloatingActionButtonLocation = previousFloatingActionButtonLocation; |
|||
this.currentFloatingActionButtonLocation = currentFloatingActionButtonLocation; |
|||
this.floatingActionButtonMoveAnimationProgress = floatingActionButtonMoveAnimationProgress; |
|||
this.floatingActionButtonMotionAnimator = floatingActionButtonMotionAnimator; |
|||
} |
|||
|
|||
public readonly EdgeInsets minInsets; |
|||
|
|||
public readonly _ScaffoldGeometryNotifier geometryNotifier; |
|||
|
|||
public readonly FloatingActionButtonLocation previousFloatingActionButtonLocation; |
|||
|
|||
public readonly FloatingActionButtonLocation currentFloatingActionButtonLocation; |
|||
|
|||
public readonly float floatingActionButtonMoveAnimationProgress; |
|||
|
|||
public readonly FloatingActionButtonAnimator floatingActionButtonMotionAnimator; |
|||
|
|||
public override void performLayout(Size size) { |
|||
BoxConstraints looseConstraints = BoxConstraints.loose(size); |
|||
|
|||
BoxConstraints fullWidthConstraints = looseConstraints.tighten(width: size.width); |
|||
float bottom = size.height; |
|||
float contentTop = 0.0f; |
|||
float bottomWidgetsHeight = 0.0f; |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.appBar)) { |
|||
contentTop = this.layoutChild(_ScaffoldSlot.appBar, fullWidthConstraints).height; |
|||
this.positionChild(_ScaffoldSlot.appBar, Offset.zero); |
|||
} |
|||
|
|||
float bottomNavigationBarTop = 0.0f; |
|||
if (this.hasChild(_ScaffoldSlot.bottomNavigationBar)) { |
|||
float bottomNavigationBarHeight = |
|||
this.layoutChild(_ScaffoldSlot.bottomNavigationBar, fullWidthConstraints).height; |
|||
bottomWidgetsHeight += bottomNavigationBarHeight; |
|||
bottomNavigationBarTop = Mathf.Max(0.0f, bottom - bottomWidgetsHeight); |
|||
this.positionChild(_ScaffoldSlot.bottomNavigationBar, new Offset(0.0f, bottomNavigationBarTop)); |
|||
} |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.persistentFooter)) { |
|||
BoxConstraints footerConstraints = new BoxConstraints( |
|||
maxWidth: fullWidthConstraints.maxWidth, |
|||
maxHeight: Mathf.Max(0.0f, bottom - bottomWidgetsHeight - contentTop) |
|||
); |
|||
float persistentFooterHeight = |
|||
this.layoutChild(_ScaffoldSlot.persistentFooter, footerConstraints).height; |
|||
bottomWidgetsHeight += persistentFooterHeight; |
|||
this.positionChild(_ScaffoldSlot.persistentFooter, |
|||
new Offset(0.0f, Mathf.Max(0.0f, bottom - bottomWidgetsHeight))); |
|||
} |
|||
|
|||
float contentBottom = Mathf.Max(0.0f, bottom - Mathf.Max(this.minInsets.bottom, bottomWidgetsHeight)); |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.body)) { |
|||
BoxConstraints bodyConstraints = new BoxConstraints( |
|||
maxWidth: fullWidthConstraints.maxWidth, |
|||
maxHeight: Mathf.Max(0.0f, contentBottom - contentTop) |
|||
); |
|||
this.layoutChild(_ScaffoldSlot.body, bodyConstraints); |
|||
this.positionChild(_ScaffoldSlot.body, new Offset(0.0f, contentTop)); |
|||
} |
|||
|
|||
Size bottomSheetSize = Size.zero; |
|||
Size snackBarSize = Size.zero; |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.bottomSheet)) { |
|||
BoxConstraints bottomSheetConstraints = new BoxConstraints( |
|||
maxWidth: fullWidthConstraints.maxWidth, |
|||
maxHeight: Mathf.Max(0.0f, contentBottom - contentTop) |
|||
); |
|||
bottomSheetSize = this.layoutChild(_ScaffoldSlot.bottomSheet, bottomSheetConstraints); |
|||
this.positionChild(_ScaffoldSlot.bottomSheet, |
|||
new Offset((size.width - bottomSheetSize.width) / 2.0f, contentBottom - bottomSheetSize.height)); |
|||
} |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.snackBar)) { |
|||
snackBarSize = this.layoutChild(_ScaffoldSlot.snackBar, fullWidthConstraints); |
|||
this.positionChild(_ScaffoldSlot.snackBar, new Offset(0.0f, contentBottom - snackBarSize.height)); |
|||
} |
|||
|
|||
Rect floatingActionButtonRect = null; |
|||
if (this.hasChild(_ScaffoldSlot.floatingActionButton)) { |
|||
Size fabSize = this.layoutChild(_ScaffoldSlot.floatingActionButton, looseConstraints); |
|||
ScaffoldPrelayoutGeometry currentGeometry = new ScaffoldPrelayoutGeometry( |
|||
bottomSheetSize: bottomSheetSize, |
|||
contentBottom: contentBottom, |
|||
contentTop: contentTop, |
|||
floatingActionButtonSize: fabSize, |
|||
minInsets: this.minInsets, |
|||
scaffoldSize: size, |
|||
snackBarSize: snackBarSize |
|||
); |
|||
Offset currentFabOffset = this.currentFloatingActionButtonLocation.getOffset(currentGeometry); |
|||
Offset previousFabOffset = this.previousFloatingActionButtonLocation.getOffset(currentGeometry); |
|||
Offset fabOffset = this.floatingActionButtonMotionAnimator.getOffset( |
|||
begin: previousFabOffset, |
|||
end: currentFabOffset, |
|||
progress: this.floatingActionButtonMoveAnimationProgress |
|||
); |
|||
this.positionChild(_ScaffoldSlot.floatingActionButton, fabOffset); |
|||
floatingActionButtonRect = fabOffset & fabSize; |
|||
} |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.statusBar)) { |
|||
this.layoutChild(_ScaffoldSlot.statusBar, fullWidthConstraints.tighten(height: this.minInsets.top)); |
|||
this.positionChild(_ScaffoldSlot.statusBar, Offset.zero); |
|||
} |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.drawer)) { |
|||
this.layoutChild(_ScaffoldSlot.drawer, BoxConstraints.tight(size)); |
|||
this.positionChild(_ScaffoldSlot.drawer, Offset.zero); |
|||
} |
|||
|
|||
if (this.hasChild(_ScaffoldSlot.endDrawer)) { |
|||
this.layoutChild(_ScaffoldSlot.endDrawer, BoxConstraints.tight(size)); |
|||
this.positionChild(_ScaffoldSlot.endDrawer, Offset.zero); |
|||
} |
|||
|
|||
this.geometryNotifier._updateWith( |
|||
bottomNavigationBarTop: bottomNavigationBarTop, |
|||
floatingActionButtonArea: floatingActionButtonRect |
|||
); |
|||
} |
|||
|
|||
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) { |
|||
_ScaffoldLayout _oldDelegate = (_ScaffoldLayout) oldDelegate; |
|||
return _oldDelegate.minInsets != this.minInsets |
|||
|| _oldDelegate.floatingActionButtonMoveAnimationProgress != |
|||
this.floatingActionButtonMoveAnimationProgress |
|||
|| _oldDelegate.previousFloatingActionButtonLocation != this.previousFloatingActionButtonLocation |
|||
|| _oldDelegate.currentFloatingActionButtonLocation != this.currentFloatingActionButtonLocation; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _FloatingActionButtonTransition : StatefulWidget { |
|||
public _FloatingActionButtonTransition( |
|||
Key key = null, |
|||
Widget child = null, |
|||
Animation<float> fabMoveAnimation = null, |
|||
FloatingActionButtonAnimator fabMotionAnimator = null, |
|||
_ScaffoldGeometryNotifier geometryNotifier = null |
|||
) : base(key: key) { |
|||
D.assert(fabMoveAnimation != null); |
|||
D.assert(fabMotionAnimator != null); |
|||
this.child = child; |
|||
this.fabMoveAnimation = fabMoveAnimation; |
|||
this.fabMotionAnimator = fabMotionAnimator; |
|||
this.geometryNotifier = geometryNotifier; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly Animation<float> fabMoveAnimation; |
|||
|
|||
public readonly FloatingActionButtonAnimator fabMotionAnimator; |
|||
|
|||
public readonly _ScaffoldGeometryNotifier geometryNotifier; |
|||
|
|||
public override State createState() { |
|||
return new _FloatingActionButtonTransitionState(); |
|||
} |
|||
} |
|||
|
|||
class _FloatingActionButtonTransitionState : TickerProviderStateMixin<_FloatingActionButtonTransition> { |
|||
AnimationController _previousController; |
|||
Animation<float> _previousScaleAnimation; |
|||
Animation<float> _previousRotationAnimation; |
|||
AnimationController _currentController; |
|||
Animation<float> _currentScaleAnimation; |
|||
Animation<float> _extendedCurrentScaleAnimation; |
|||
Animation<float> _currentRotationAnimation; |
|||
Widget _previousChild; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
|
|||
this._previousController = new AnimationController( |
|||
duration: FloatingActionButtonLocationUtils.kFloatingActionButtonSegue, |
|||
vsync: this); |
|||
this._previousController.addStatusListener(this._handlePreviousAnimationStatusChanged); |
|||
|
|||
this._currentController = new AnimationController( |
|||
duration: FloatingActionButtonLocationUtils.kFloatingActionButtonSegue, |
|||
vsync: this); |
|||
|
|||
this._updateAnimations(); |
|||
|
|||
if (this.widget.child != null) { |
|||
this._currentController.setValue(1.0f); |
|||
} |
|||
else { |
|||
this._updateGeometryScale(0.0f); |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._previousController.dispose(); |
|||
this._currentController.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
|
|||
_FloatingActionButtonTransition _oldWidget = (_FloatingActionButtonTransition) oldWidget; |
|||
bool oldChildIsNull = _oldWidget.child == null; |
|||
bool newChildIsNull = this.widget.child == null; |
|||
|
|||
if (oldChildIsNull == newChildIsNull && _oldWidget.child?.key == this.widget.child?.key) { |
|||
return; |
|||
} |
|||
|
|||
if (_oldWidget.fabMotionAnimator != this.widget.fabMotionAnimator || |
|||
_oldWidget.fabMoveAnimation != this.widget.fabMoveAnimation) { |
|||
this._updateAnimations(); |
|||
} |
|||
|
|||
if (this._previousController.status == AnimationStatus.dismissed) { |
|||
float currentValue = this._currentController.value; |
|||
if (currentValue == 0.0f || _oldWidget.child == null) { |
|||
this._previousChild = null; |
|||
if (this.widget.child != null) { |
|||
this._currentController.forward(); |
|||
} |
|||
} |
|||
else { |
|||
this._previousChild = _oldWidget.child; |
|||
this._previousController.setValue(currentValue); |
|||
this._previousController.reverse(); |
|||
this._currentController.setValue(0.0f); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static Animatable<float> _entranceTurnTween = new FloatTween( |
|||
begin: 1.0f - FloatingActionButtonLocationUtils.kFloatingActionButtonTurnInterval, |
|||
end: 1.0f |
|||
).chain(new CurveTween(curve: Curves.easeIn)); |
|||
|
|||
void _updateAnimations() { |
|||
CurvedAnimation previousExitScaleAnimation = new CurvedAnimation( |
|||
parent: this._previousController, |
|||
curve: Curves.easeIn |
|||
); |
|||
Animation<float> previousExitRotationAnimation = new FloatTween(begin: 1.0f, end: 1.0f).animate( |
|||
new CurvedAnimation( |
|||
parent: this._previousController, |
|||
curve: Curves.easeIn |
|||
) |
|||
); |
|||
|
|||
CurvedAnimation currentEntranceScaleAnimation = new CurvedAnimation( |
|||
parent: this._currentController, |
|||
curve: Curves.easeIn |
|||
); |
|||
Animation<float> currentEntranceRotationAnimation = this._currentController.drive(_entranceTurnTween); |
|||
Animation<float> moveScaleAnimation = |
|||
this.widget.fabMotionAnimator.getScaleAnimation(parent: this.widget.fabMoveAnimation); |
|||
Animation<float> moveRotationAnimation = |
|||
this.widget.fabMotionAnimator.getRotationAnimation(parent: this.widget.fabMoveAnimation); |
|||
|
|||
this._previousScaleAnimation = new AnimationMin(moveScaleAnimation, previousExitScaleAnimation); |
|||
this._currentScaleAnimation = new AnimationMin(moveScaleAnimation, currentEntranceScaleAnimation); |
|||
this._extendedCurrentScaleAnimation = |
|||
this._currentScaleAnimation.drive(new CurveTween(curve: new Interval(0.0f, 0.1f))); |
|||
|
|||
this._previousRotationAnimation = |
|||
new TrainHoppingAnimation(previousExitRotationAnimation, moveRotationAnimation); |
|||
this._currentRotationAnimation = |
|||
new TrainHoppingAnimation(currentEntranceRotationAnimation, moveRotationAnimation); |
|||
|
|||
this._currentScaleAnimation.addListener(this._onProgressChanged); |
|||
this._previousScaleAnimation.addListener(this._onProgressChanged); |
|||
} |
|||
|
|||
void _handlePreviousAnimationStatusChanged(AnimationStatus status) { |
|||
this.setState(() => { |
|||
if (status == AnimationStatus.dismissed) { |
|||
D.assert(this._currentController.status == AnimationStatus.dismissed); |
|||
if (this.widget.child != null) { |
|||
this._currentController.forward(); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
bool _isExtendedFloatingActionButton(Widget widget) { |
|||
if (!(widget is FloatingActionButton)) { |
|||
return false; |
|||
} |
|||
|
|||
FloatingActionButton fab = (FloatingActionButton) widget; |
|||
return fab.isExtended; |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<Widget> children = new List<Widget>(); |
|||
|
|||
if (this._previousController.status != AnimationStatus.dismissed) { |
|||
if (this._isExtendedFloatingActionButton(this._previousChild)) { |
|||
children.Add(new FadeTransition( |
|||
opacity: this._previousScaleAnimation, |
|||
child: this._previousChild)); |
|||
} |
|||
else { |
|||
children.Add(new ScaleTransition( |
|||
scale: this._previousScaleAnimation, |
|||
child: new RotationTransition( |
|||
turns: this._previousRotationAnimation, |
|||
child: this._previousChild))); |
|||
} |
|||
} |
|||
|
|||
if (this._isExtendedFloatingActionButton(this.widget.child)) { |
|||
children.Add(new ScaleTransition( |
|||
scale: this._extendedCurrentScaleAnimation, |
|||
child: new FadeTransition( |
|||
opacity: this._currentScaleAnimation, |
|||
child: this.widget.child |
|||
) |
|||
)); |
|||
} |
|||
else { |
|||
children.Add(new ScaleTransition( |
|||
scale: this._currentScaleAnimation, |
|||
child: new RotationTransition( |
|||
turns: this._currentRotationAnimation, |
|||
child: this.widget.child |
|||
) |
|||
)); |
|||
} |
|||
|
|||
return new Stack( |
|||
alignment: Alignment.centerRight, |
|||
children: children |
|||
); |
|||
} |
|||
|
|||
|
|||
void _onProgressChanged() { |
|||
this._updateGeometryScale(Mathf.Max(this._previousScaleAnimation.value, this._currentScaleAnimation.value)); |
|||
} |
|||
|
|||
void _updateGeometryScale(float scale) { |
|||
this.widget.geometryNotifier._updateWith( |
|||
floatingActionButtonScale: scale |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class Scaffold : StatefulWidget { |
|||
public Scaffold( |
|||
Key key = null, |
|||
PreferredSizeWidget appBar = null, |
|||
Widget body = null, |
|||
Widget floatingActionButton = null, |
|||
FloatingActionButtonLocation floatingActionButtonLocation = null, |
|||
FloatingActionButtonAnimator floatingActionButtonAnimator = null, |
|||
List<Widget> persistentFooterButtons = null, |
|||
Widget drawer = null, |
|||
Widget endDrawer = null, |
|||
Widget bottomNavigationBar = null, |
|||
Widget bottomSheet = null, |
|||
Color backgroundColor = null, |
|||
bool resizeToAvoidBottomPadding = true, |
|||
bool primary = true) : base(key: key) { |
|||
this.appBar = appBar; |
|||
this.body = body; |
|||
this.floatingActionButton = floatingActionButton; |
|||
this.floatingActionButtonLocation = floatingActionButtonLocation; |
|||
this.floatingActionButtonAnimator = floatingActionButtonAnimator; |
|||
this.persistentFooterButtons = persistentFooterButtons; |
|||
this.drawer = drawer; |
|||
this.endDrawer = endDrawer; |
|||
this.bottomNavigationBar = bottomNavigationBar; |
|||
this.bottomSheet = bottomSheet; |
|||
this.backgroundColor = backgroundColor; |
|||
this.resizeToAvoidBottomPadding = resizeToAvoidBottomPadding; |
|||
this.primary = primary; |
|||
} |
|||
|
|||
public readonly PreferredSizeWidget appBar; |
|||
|
|||
public readonly Widget body; |
|||
|
|||
public readonly Widget floatingActionButton; |
|||
|
|||
public readonly FloatingActionButtonLocation floatingActionButtonLocation; |
|||
|
|||
public readonly FloatingActionButtonAnimator floatingActionButtonAnimator; |
|||
|
|||
public readonly List<Widget> persistentFooterButtons; |
|||
|
|||
public readonly Widget drawer; |
|||
|
|||
public readonly Widget endDrawer; |
|||
|
|||
public readonly Color backgroundColor; |
|||
|
|||
public readonly Widget bottomNavigationBar; |
|||
|
|||
public readonly Widget bottomSheet; |
|||
|
|||
public readonly bool resizeToAvoidBottomPadding; |
|||
|
|||
public readonly bool primary; |
|||
|
|||
public static ScaffoldState of(BuildContext context, bool nullOk = false) { |
|||
D.assert(context != null); |
|||
ScaffoldState result = (ScaffoldState)context.ancestorStateOfType(new TypeMatcher<ScaffoldState>()); |
|||
if (nullOk || result != null) { |
|||
return result; |
|||
} |
|||
|
|||
throw new UIWidgetsError( |
|||
"Scaffold.of() called with a context that does not contain a Scaffold.\n" + |
|||
"No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). " + |
|||
"This usually happens when the context provided is from the same StatefulWidget as that " + |
|||
"whose build function actually creates the Scaffold widget being sought.\n" + |
|||
"There are several ways to avoid this problem. The simplest is to use a Builder to get a " + |
|||
"context that is \"under\" the Scaffold. For an example of this, please see the " + |
|||
"documentation for Scaffold.of():\n" + |
|||
" https://docs.flutter.io/flutter/material/Scaffold/of.html\n" + |
|||
"A more efficient solution is to split your build function into several widgets. This " + |
|||
"introduces a new context from which you can obtain the Scaffold. In this solution, " + |
|||
"you would have an outer widget that creates the Scaffold populated by instances of " + |
|||
"your new inner widgets, and then in these inner widgets you would use Scaffold.of().\n" + |
|||
"A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, " + |
|||
"then use the key.currentState property to obtain the ScaffoldState rather than " + |
|||
"using the Scaffold.of() function.\n" + |
|||
"The context used was:\n" + context); |
|||
} |
|||
|
|||
static ValueListenable<ScaffoldGeometry> geometryOf(BuildContext context) { |
|||
_ScaffoldScope scaffoldScope = (_ScaffoldScope)context.inheritFromWidgetOfExactType(typeof(_ScaffoldScope)); |
|||
if (scaffoldScope == null) { |
|||
throw new UIWidgetsError( |
|||
"Scaffold.geometryOf() called with a context that does not contain a Scaffold.\n" + |
|||
"This usually happens when the context provided is from the same StatefulWidget as that " + |
|||
"whose build function actually creates the Scaffold widget being sought.\n" + |
|||
"There are several ways to avoid this problem. The simplest is to use a Builder to get a " + |
|||
"context that is \"under\" the Scaffold. For an example of this, please see the " + |
|||
"documentation for Scaffold.of():\n" + |
|||
" https://docs.flutter.io/flutter/material/Scaffold/of.html\n" + |
|||
"A more efficient solution is to split your build function into several widgets. This " + |
|||
"introduces a new context from which you can obtain the Scaffold. In this solution, " + |
|||
"you would have an outer widget that creates the Scaffold populated by instances of " + |
|||
"your new inner widgets, and then in these inner widgets you would use Scaffold.geometryOf().\n" + |
|||
"The context used was:\n" + context); |
|||
} |
|||
|
|||
return scaffoldScope.geometryNotifier; |
|||
} |
|||
|
|||
static bool hasDrawer(BuildContext context, bool registerForUpdates = true) { |
|||
D.assert(context != null); |
|||
if (registerForUpdates) { |
|||
_ScaffoldScope scaffold = (_ScaffoldScope)context.inheritFromWidgetOfExactType(typeof(_ScaffoldScope)); |
|||
return scaffold?.hasDrawer ?? false; |
|||
} |
|||
else { |
|||
ScaffoldState scaffold = context.ancestorStateOfType(new TypeMatcher<ScaffoldState>()); |
|||
return scaffold?.hasDrawer ?? false; |
|||
} |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new ScaffoldState(); |
|||
} |
|||
} |
|||
|
|||
public class ScaffoldState : TickerProviderStateMixin<Scaffold> { |
|||
|
|||
public readonly GlobalKey<DrawerControllerState> _drawerKey = GlobalKey<DrawerControllerState>.key(); |
|||
public readonly GlobalKey<DrawerControllerState> _endDrawerKey = GlobalKey<DrawerControllerState>.key(); |
|||
|
|||
public bool hasDrawer { |
|||
get { return this.widget.drawer != null; } |
|||
} |
|||
|
|||
public bool hasEndDrawer { |
|||
get { return this.widget.endDrawer != null; } |
|||
} |
|||
|
|||
bool _drawerOpened = false; |
|||
bool _endDrawerOpened = false; |
|||
|
|||
public bool isDrawerOpen { |
|||
get { return this._drawerOpened; } |
|||
} |
|||
|
|||
public bool isEndDrawerOpen { |
|||
get { return this._endDrawerOpened; } |
|||
} |
|||
|
|||
void _drawerOpenedCallback(bool isOpened) { |
|||
this.setState(() => { this._drawerOpened = isOpened; }); |
|||
} |
|||
|
|||
void _endDrawerOpenedCallback(bool isOpened) { |
|||
this.setState(() => { this._endDrawerOpened = isOpened; }); |
|||
} |
|||
|
|||
|
|||
public void openDrawer() { |
|||
if (this._endDrawerKey.currentState != null && this._endDrawerOpened) { |
|||
this._endDrawerKey.currentState.close(); |
|||
} |
|||
|
|||
this._drawerKey.currentState?.open(); |
|||
} |
|||
|
|||
public void openEndDrawer() { |
|||
if (this._drawerKey.currentState != null && this._drawerOpened) { |
|||
this._drawerKey.currentState.close(); |
|||
} |
|||
this._endDrawerKey.currentState?.open(); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
class _ScaffoldScope : InheritedWidget { |
|||
public _ScaffoldScope( |
|||
bool? hasDrawer = null, |
|||
_ScaffoldGeometryNotifier geometryNotifier = null, |
|||
Widget child = null |
|||
) : base(child: child) { |
|||
D.assert(hasDrawer != null); |
|||
D.assert(child != null); |
|||
D.assert(geometryNotifier != null); |
|||
this.hasDrawer = hasDrawer.Value; |
|||
this.geometryNotifier = geometryNotifier; |
|||
} |
|||
|
|||
public readonly bool hasDrawer; |
|||
public readonly _ScaffoldGeometryNotifier geometryNotifier; |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) { |
|||
_ScaffoldScope _oldWidget = (_ScaffoldScope) oldWidget; |
|||
return this.hasDrawer != _oldWidget.hasDrawer; |
|||
} |
|||
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2ed8ea3a4f90842e7884a5aff0ca6ec3 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
|
|||
static class SnackBarUtils { |
|||
public const float _kSnackBarPadding = 24.0f; |
|||
public const float _kSingleLineVerticalPadding = 14.0f; |
|||
public static Color _kSnackBackground = new Color(0xFF323232); |
|||
|
|||
public static TimeSpan _kSnackBarTransitionDuration = new TimeSpan(0, 0, 0, 0, 250); |
|||
public static TimeSpan _kSnackBarDisplayDuration = new TimeSpan(0, 0, 0, 0, 4000); |
|||
public static Curve _snackBarHeightCurve = Curves.fastOutSlowIn; |
|||
public static Curve _snackBarFadeCurve = new Interval(0.72f, 1.0f, curve: Curves.fastOutSlowIn); |
|||
} |
|||
|
|||
public enum SnackBarClosedReason { |
|||
action, |
|||
dismiss, |
|||
swipe, |
|||
hide, |
|||
remove, |
|||
timeout |
|||
} |
|||
|
|||
public class SnackBarAction : StatefulWidget { |
|||
public SnackBarAction( |
|||
Key key = null, |
|||
Color textColor = null, |
|||
Color disabledTextColor = null, |
|||
string label = null, |
|||
VoidCallback onPressed = null |
|||
) : base(key: key) { |
|||
D.assert(label != null); |
|||
D.assert(onPressed != null); |
|||
this.textColor = textColor; |
|||
this.disabledTextColor = disabledTextColor; |
|||
this.label = label; |
|||
this.onPressed = onPressed; |
|||
} |
|||
|
|||
public readonly Color textColor; |
|||
|
|||
public readonly Color disabledTextColor; |
|||
|
|||
public readonly string label; |
|||
|
|||
public readonly VoidCallback onPressed; |
|||
|
|||
public override State createState() { |
|||
return new _SnackBarActionState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _SnackBarActionState : State<SnackBarAction> { |
|||
bool _haveTriggeredAction = false; |
|||
|
|||
void _handlePressed() { |
|||
if (this._haveTriggeredAction) { |
|||
return; |
|||
} |
|||
|
|||
this.setState(() => { |
|||
this._haveTriggeredAction = true; |
|||
}); |
|||
|
|||
this.widget.onPressed(); |
|||
Scaffold.of(this.context).hideCurrentSnackBar(reason: SnackBarClosedReason.action); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new FlatButton( |
|||
onPressed: this._haveTriggeredAction ? (VoidCallback)null : this._handlePressed, |
|||
child: new Text(this.widget.label), |
|||
textColor: this.widget.textColor, |
|||
disabledTextColor: this.widget.disabledTextColor |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class SnackBar : StatelessWidget { |
|||
public SnackBar( |
|||
Key key = null, |
|||
Widget content = null, |
|||
Color backgroundColor = null, |
|||
SnackBarAction action = null, |
|||
TimeSpan? duration = null, |
|||
Animation<float> animation = null) : base(key: key) { |
|||
duration = duration ?? SnackBarUtils._kSnackBarDisplayDuration; |
|||
D.assert(content != null); |
|||
this.content = content; |
|||
this.backgroundColor = backgroundColor; |
|||
this.action = action; |
|||
this.duration = duration.Value; |
|||
this.animation = animation; |
|||
} |
|||
|
|||
public readonly Widget content; |
|||
|
|||
public readonly Color backgroundColor; |
|||
|
|||
public readonly SnackBarAction action; |
|||
|
|||
public readonly TimeSpan duration; |
|||
|
|||
public readonly Animation<float> animation; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
MediaQueryData mediaQueryData = MediaQuery.of(context); |
|||
D.assert(this.animation != null); |
|||
|
|||
ThemeData theme = Theme.of(context); |
|||
ThemeData darkTheme = new ThemeData( |
|||
brightness: Brightness.dark, |
|||
accentColor: theme.accentColor, |
|||
accentColorBrightness: theme.accentColorBrightness |
|||
); |
|||
|
|||
List<Widget> children = new List<Widget> { |
|||
new SizedBox(width: SnackBarUtils._kSnackBarPadding), |
|||
new Expanded( |
|||
child: new Container( |
|||
padding: EdgeInsets.symmetric(vertical: SnackBarUtils._kSingleLineVerticalPadding), |
|||
child: new DefaultTextStyle( |
|||
style: darkTheme.textTheme.subhead, |
|||
child: this.content) |
|||
) |
|||
) |
|||
}; |
|||
|
|||
if (this.action != null) { |
|||
children.Add(ButtonTheme.bar( |
|||
padding: EdgeInsets.symmetric(horizontal: SnackBarUtils._kSnackBarPadding), |
|||
textTheme: ButtonTextTheme.accent, |
|||
child: this.action |
|||
)); |
|||
} |
|||
else { |
|||
children.Add(new SizedBox(width: SnackBarUtils._kSnackBarPadding)); |
|||
} |
|||
|
|||
CurvedAnimation heightAnimation = new CurvedAnimation(parent: this.animation, curve: SnackBarUtils._snackBarHeightCurve); |
|||
CurvedAnimation fadeAnimation = new CurvedAnimation(parent: this.animation, curve: SnackBarUtils._snackBarFadeCurve, reverseCurve: new Threshold(0.0f)); |
|||
Widget snackbar = new SafeArea( |
|||
top: false, |
|||
child: new Row( |
|||
children: children, |
|||
crossAxisAlignment: CrossAxisAlignment.center |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.rendering; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class AnnotatedRegion<T> : SingleChildRenderObjectWidget |
|||
where T : class { |
|||
public AnnotatedRegion( |
|||
Key key = null, |
|||
Widget child = null, |
|||
T value = null, |
|||
bool sized = true) : base(key: key, child: child) { |
|||
D.assert(value != null); |
|||
D.assert(child != null); |
|||
this.value = value; |
|||
this.sized = sized; |
|||
} |
|||
|
|||
public readonly T value; |
|||
|
|||
public readonly bool sized; |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new RenderAnnotatedRegion<T>(value: this.value, sized: this.sized); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
RenderAnnotatedRegion<T> _renderObject = (RenderAnnotatedRegion<T>) renderObject; |
|||
_renderObject.value = this.value; |
|||
_renderObject.sized = this.sized; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b7edf2448377d4d3b9b9f63eb136266b |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 60513bb9173ce47ad8d4c7840bcfe836 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue