Yuncong Zhang
6 年前
当前提交
c05d7130
共有 56 个文件被更改,包括 5115 次插入 和 92 次删除
-
3Runtime/animation/tween.cs
-
6Runtime/material/arc.cs
-
2Runtime/material/debug.cs
-
22Runtime/material/divider.cs
-
175Runtime/material/expansion_tile.cs
-
94Runtime/material/icon_button.cs
-
6Runtime/material/ink_well.cs
-
31Runtime/material/material.cs
-
5Runtime/material/shadows.cs
-
30Runtime/material/utils.cs
-
125Runtime/rendering/proxy_box.cs
-
2Runtime/service/system_chrome.cs
-
120Runtime/widgets/basic.cs
-
191Runtime/widgets/implicit_animations.cs
-
33Runtime/widgets/transitions.cs
-
11Samples/UIWidgetSample/MaterialCanvas.cs
-
11Runtime/material/divider.cs.meta
-
304Runtime/material/drawer.cs
-
11Runtime/material/drawer.cs.meta
-
71Runtime/material/drawer_header.cs
-
11Runtime/material/drawer_header.cs.meta
-
93Runtime/material/expand_icon.cs
-
11Runtime/material/expand_icon.cs.meta
-
318Runtime/material/expansion_panel.cs
-
11Runtime/material/expansion_panel.cs.meta
-
53Runtime/material/grid_tile.cs
-
11Runtime/material/grid_tile.cs.meta
-
11Runtime/material/icon_button.cs.meta
-
7Runtime/material/icons.cs
-
11Runtime/material/icons.cs.meta
-
841Runtime/material/list_tile.cs
-
11Runtime/material/list_tile.cs.meta
-
714Runtime/material/mergeable_material.cs
-
11Runtime/material/mergeable_material.cs.meta
-
269Runtime/material/tooltip.cs
-
11Runtime/material/tooltip.cs.meta
-
51Runtime/painting/geometry.cs
-
11Runtime/painting/geometry.cs.meta
-
204Runtime/rendering/animated_size.cs
-
11Runtime/rendering/animated_size.cs.meta
-
276Runtime/rendering/list_body.cs
-
11Runtime/rendering/list_body.cs.meta
-
16Runtime/rendering/tweens.cs
-
11Runtime/rendering/tweens.cs.meta
-
20Runtime/utils/axis_direction.cs
-
11Runtime/utils/axis_direction.cs.meta
-
228Runtime/widgets/animated_cross_fade.cs
-
11Runtime/widgets/animated_cross_fade.cs.meta
-
49Runtime/widgets/animated_size.cs
-
11Runtime/widgets/animated_size.cs.meta
-
63Runtime/widgets/safe_area.cs
-
11Runtime/widgets/safe_area.cs.meta
-
451Runtime/widgets/single_child_scroll_view.cs
-
11Runtime/widgets/single_child_scroll_view.cs.meta
-
92Samples/UIWidgetSample/ExpansionPanelCanvas.cs
-
11Samples/UIWidgetSample/ExpansionPanelCanvas.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.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
public class expansion_tile { |
|||
|
|||
public class ExpansionTile : StatefulWidget { |
|||
public ExpansionTile( |
|||
Key key = null, |
|||
Widget leading = null, |
|||
Widget title = null, |
|||
Color backgroundColor = null, |
|||
ValueChanged<bool> onExpansionChanged = null, |
|||
List<Widget> children = null, |
|||
Widget trailing = null, |
|||
bool initiallyExpanded = false |
|||
) : base(key: key) { |
|||
D.assert(title != null); |
|||
this.leading = leading; |
|||
this.title = title; |
|||
this.backgroundColor = backgroundColor; |
|||
this.onExpansionChanged = onExpansionChanged; |
|||
this.children = children ?? new List<Widget>(); |
|||
this.trailing = trailing; |
|||
this.initiallyExpanded = initiallyExpanded; |
|||
} |
|||
|
|||
public readonly Widget leading; |
|||
|
|||
public readonly Widget title; |
|||
|
|||
public readonly ValueChanged<bool> onExpansionChanged; |
|||
|
|||
public readonly List<Widget> children; |
|||
|
|||
public readonly Color backgroundColor; |
|||
|
|||
public readonly Widget trailing; |
|||
|
|||
public readonly bool initiallyExpanded; |
|||
|
|||
public override State createState() { |
|||
return new _ExpansionTileState(); |
|||
} |
|||
} |
|||
|
|||
public class _ExpansionTileState : SingleTickerProviderStateMixin<ExpansionTile> { |
|||
static readonly Animatable<double> _easeOutTween = new CurveTween(curve: Curves.easeOut); |
|||
static readonly Animatable<double> _easeInTween = new CurveTween(curve: Curves.easeIn); |
|||
static readonly Animatable<double> _halfTween = new DoubleTween(begin: 0.0, end: 0.5); |
|||
|
|||
readonly ColorTween _borderColorTween = new ColorTween(); |
|||
readonly ColorTween _headerColorTween = new ColorTween(); |
|||
readonly ColorTween _iconColorTween = new ColorTween(); |
|||
readonly ColorTween _backgroundColorTween = new ColorTween(); |
|||
|
|||
AnimationController _controller; |
|||
Animation<double> _iconTurns; |
|||
Animation<double> _heightFactor; |
|||
Animation<Color> _borderColor; |
|||
Animation<Color> _headerColor; |
|||
Animation<Color> _iconColor; |
|||
Animation<Color> _backgroundColor; |
|||
|
|||
bool _isExpanded = false; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController(duration: ExpansionTileUtils._kExpand, vsync: this); |
|||
this._heightFactor = this._controller.drive(_easeInTween); |
|||
this._iconTurns = this._controller.drive(_halfTween.chain(_easeInTween)); |
|||
this._borderColor = this._controller.drive(this._borderColorTween.chain(_easeOutTween)); |
|||
this._headerColor = this._controller.drive(this._headerColorTween.chain(_easeInTween)); |
|||
this._iconColor = this._controller.drive(this._iconColorTween.chain(_easeInTween)); |
|||
this._backgroundColor = this._controller.drive(this._backgroundColorTween.chain(_easeOutTween)); |
|||
|
|||
this._isExpanded = PageStorage.of(this.context)?.readState(this.context) == null |
|||
? this.widget.initiallyExpanded |
|||
: (bool) PageStorage.of(this.context)?.readState(this.context); |
|||
|
|||
if (this._isExpanded) { |
|||
this._controller.setValue(1.0); |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _handleTap() { |
|||
this.setState(() => { |
|||
this._isExpanded = !this._isExpanded; |
|||
if (this._isExpanded) { |
|||
this._controller.forward(); |
|||
} |
|||
else { |
|||
this._controller.reverse().Then(() => { |
|||
if (!this.mounted) { |
|||
return; |
|||
} |
|||
|
|||
this.setState(() => { }); |
|||
}); |
|||
} |
|||
|
|||
PageStorage.of(this.context)?.writeState(this.context, this._isExpanded); |
|||
}); |
|||
if (this.widget.onExpansionChanged != null) { |
|||
this.widget.onExpansionChanged(this._isExpanded); |
|||
} |
|||
} |
|||
|
|||
Widget _buildChildren(BuildContext context, Widget child) { |
|||
Color borderSideColor = this._borderColor.value ?? Colors.transparent; |
|||
Color titleColor = this._headerColor.value; |
|||
|
|||
return new Container( |
|||
decoration: new BoxDecoration( |
|||
color: this._backgroundColor.value ?? Colors.transparent, |
|||
border: new Border( |
|||
top: new BorderSide(color: borderSideColor), |
|||
bottom: new BorderSide(color: borderSideColor))), |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget> { |
|||
IconTheme.merge( |
|||
data: new IconThemeData(color: this._iconColor.value), |
|||
child: new ListTile( |
|||
onTap: this._handleTap, |
|||
leading: this.widget.leading, |
|||
title: new DefaultTextStyle( |
|||
style: Theme.of(this.context).textTheme.subhead.copyWith(color: titleColor), |
|||
child: this.widget.title), |
|||
trailing: this.widget.trailing ?? new RotationTransition( |
|||
turns: this._iconTurns, |
|||
//todo xingwei.zhu: add Icons.expand_more
|
|||
child: null) |
|||
) |
|||
), |
|||
new ClipRect( |
|||
child: new Align( |
|||
heightFactor: this._heightFactor.value, |
|||
child: child) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
public override void didChangeDependencies() { |
|||
ThemeData theme = Theme.of(this.context); |
|||
this._borderColorTween.end = theme.dividerColor; |
|||
this._headerColorTween.begin = theme.textTheme.subhead.color; |
|||
this._headerColorTween.end = theme.accentColor; |
|||
this._iconColorTween.begin = theme.unselectedWidgetColor; |
|||
this._iconColorTween.end = theme.accentColor; |
|||
this._backgroundColorTween.end = this.widget.backgroundColor; |
|||
base.didChangeDependencies(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
bool closed = !this._isExpanded && this._controller.isDismissed; |
|||
return new AnimatedBuilder( |
|||
animation: this._controller.view, |
|||
builder: this._buildChildren, |
|||
child: closed |
|||
? null |
|||
: new Column( |
|||
children: this.widget.children)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: defd4aeb126394fa09828fd8ad695931 |
|||
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.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public enum DrawerAlignment { |
|||
start, |
|||
end |
|||
} |
|||
|
|||
public class Drawer : StatelessWidget { |
|||
public Drawer( |
|||
Key key = null, |
|||
double elevation = 16.0, |
|||
Widget child = null) : base(key: key) { |
|||
this.elevation = elevation; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly double elevation; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new ConstrainedBox( |
|||
constraints: BoxConstraints.expand(width: DrawerUtils._kWidth), |
|||
child: new Material( |
|||
elevation: this.elevation, |
|||
child: this.child |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public delegate void DrawerCallback(bool isOpened); |
|||
|
|||
|
|||
public class DrawerController : StatefulWidget { |
|||
public DrawerController( |
|||
GlobalKey key = null, |
|||
Widget child = null, |
|||
DrawerAlignment? alignment = null, |
|||
DrawerCallback drawerCallback = null) : base(key: key) { |
|||
D.assert(child != null); |
|||
D.assert(alignment != null); |
|||
this.child = child; |
|||
this.alignment = alignment ?? DrawerAlignment.start; |
|||
this.drawerCallback = drawerCallback; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public readonly DrawerAlignment alignment; |
|||
|
|||
public readonly DrawerCallback drawerCallback; |
|||
|
|||
public override State createState() { |
|||
return new DrawerControllerState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class DrawerControllerState : SingleTickerProviderStateMixin<DrawerController> { |
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController(duration: DrawerUtils._kBaseSettleDuration, vsync: this); |
|||
this._controller.addListener(this._animationChanged); |
|||
this._controller.addStatusListener(this._animationStatusChanged); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._historyEntry?.remove(); |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _animationChanged() { |
|||
this.setState(() => { }); |
|||
} |
|||
|
|||
|
|||
LocalHistoryEntry _historyEntry; |
|||
readonly FocusScopeNode _focusScopeNode = new FocusScopeNode(); |
|||
|
|||
|
|||
void _ensureHistoryEntry() { |
|||
if (this._historyEntry == null) { |
|||
ModalRoute route = ModalRoute.of(this.context); |
|||
if (route != null) { |
|||
this._historyEntry = new LocalHistoryEntry(onRemove: this._handleHistoryEntryRemoved); |
|||
route.addLocalHistoryEntry(this._historyEntry); |
|||
FocusScope.of(this.context).setFirstFocus(this._focusScopeNode); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _animationStatusChanged(AnimationStatus status) { |
|||
switch (status) { |
|||
case AnimationStatus.forward: |
|||
this._ensureHistoryEntry(); |
|||
break; |
|||
case AnimationStatus.reverse: |
|||
this._historyEntry?.remove(); |
|||
this._historyEntry = null; |
|||
break; |
|||
case AnimationStatus.dismissed: |
|||
break; |
|||
case AnimationStatus.completed: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void _handleHistoryEntryRemoved() { |
|||
this._historyEntry = null; |
|||
this.close(); |
|||
} |
|||
|
|||
AnimationController _controller; |
|||
|
|||
|
|||
void _handleDragDown(DragDownDetails details) { |
|||
this._controller.stop(); |
|||
this._ensureHistoryEntry(); |
|||
} |
|||
|
|||
void _handleDragCancel() { |
|||
if (this._controller.isDismissed || this._controller.isAnimating) { |
|||
return; |
|||
} |
|||
|
|||
if (this._controller.value < 0.5) { |
|||
this.close(); |
|||
} |
|||
else { |
|||
this.open(); |
|||
} |
|||
} |
|||
|
|||
public readonly GlobalKey _drawerKey = GlobalKey.key(); |
|||
|
|||
|
|||
double _width { |
|||
get { |
|||
RenderBox box = (RenderBox) this._drawerKey.currentContext?.findRenderObject(); |
|||
if (box != null) { |
|||
return box.size.width; |
|||
} |
|||
|
|||
return DrawerUtils._kWidth; |
|||
} |
|||
} |
|||
|
|||
bool _previouslyOpened = false; |
|||
|
|||
void _move(DragUpdateDetails details) { |
|||
double delta = (details.primaryDelta ?? 0) / this._width; |
|||
switch (this.widget.alignment) { |
|||
case DrawerAlignment.start: |
|||
break; |
|||
case DrawerAlignment.end: |
|||
delta = -delta; |
|||
break; |
|||
} |
|||
|
|||
this._controller.setValue(this._controller.value + delta); |
|||
|
|||
bool opened = this._controller.value > 0.5 ? true : false; |
|||
if (opened != this._previouslyOpened && this.widget.drawerCallback != null) { |
|||
this.widget.drawerCallback(opened); |
|||
} |
|||
|
|||
this._previouslyOpened = opened; |
|||
} |
|||
|
|||
void _settle(DragEndDetails details) { |
|||
if (this._controller.isDismissed) { |
|||
return; |
|||
} |
|||
|
|||
if (details.velocity.pixelsPerSecond.dx.abs() >= DrawerUtils._kMinFlingVelocity) { |
|||
double visualVelocity = details.velocity.pixelsPerSecond.dx / DrawerUtils._kWidth; |
|||
switch (this.widget.alignment) { |
|||
case DrawerAlignment.start: |
|||
break; |
|||
case DrawerAlignment.end: |
|||
visualVelocity = -visualVelocity; |
|||
break; |
|||
} |
|||
|
|||
this._controller.fling(velocity: visualVelocity); |
|||
} |
|||
else if (this._controller.value < 0.5) { |
|||
this.close(); |
|||
} |
|||
else { |
|||
this.open(); |
|||
} |
|||
} |
|||
|
|||
void open() { |
|||
this._controller.fling(velocity: 1.0); |
|||
if (this.widget.drawerCallback != null) { |
|||
this.widget.drawerCallback(true); |
|||
} |
|||
} |
|||
|
|||
void close() { |
|||
this._controller.fling(velocity: -1.0); |
|||
if (this.widget.drawerCallback != null) { |
|||
this.widget.drawerCallback(false); |
|||
} |
|||
} |
|||
|
|||
ColorTween _color = new ColorTween(begin: Colors.transparent, end: Colors.black54); |
|||
GlobalKey _gestureDetectorKey = GlobalKey.key(); |
|||
|
|||
Alignment _drawerOuterAlignment { |
|||
get { |
|||
switch (this.widget.alignment) { |
|||
case DrawerAlignment.start: |
|||
return Alignment.centerLeft; |
|||
case DrawerAlignment.end: |
|||
return Alignment.centerRight; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
|
|||
Alignment _drawerInnerAlignment { |
|||
get { |
|||
switch (this.widget.alignment) { |
|||
case DrawerAlignment.start: |
|||
return Alignment.centerRight; |
|||
case DrawerAlignment.end: |
|||
return Alignment.centerLeft; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
|
|||
Widget _buildDrawer(BuildContext context) { |
|||
bool drawerIsStart = this.widget.alignment == DrawerAlignment.start; |
|||
EdgeInsets padding = MediaQuery.of(context).padding; |
|||
double dragAreaWidth = drawerIsStart ? padding.left : padding.right; |
|||
|
|||
dragAreaWidth = Math.Max(dragAreaWidth, DrawerUtils._kEdgeDragWidth); |
|||
if (this._controller.status == AnimationStatus.dismissed) { |
|||
return new Align( |
|||
alignment: this._drawerOuterAlignment, |
|||
child: new GestureDetector( |
|||
key: this._gestureDetectorKey, |
|||
onHorizontalDragUpdate: this._move, |
|||
onHorizontalDragEnd: this._settle, |
|||
behavior: HitTestBehavior.translucent, |
|||
child: new Container(width: dragAreaWidth) |
|||
) |
|||
); |
|||
} |
|||
else { |
|||
return new GestureDetector( |
|||
key: this._gestureDetectorKey, |
|||
onHorizontalDragDown: this._handleDragDown, |
|||
onHorizontalDragUpdate: this._move, |
|||
onHorizontalDragEnd: this._settle, |
|||
onHorizontalDragCancel: this._handleDragCancel, |
|||
child: new RepaintBoundary( |
|||
child: new Stack( |
|||
children: new List<Widget> { |
|||
new Align( |
|||
alignment: this._drawerOuterAlignment, |
|||
child: new Align( |
|||
alignment: this._drawerInnerAlignment, |
|||
widthFactor: this._controller.value, |
|||
child: new RepaintBoundary( |
|||
child: new FocusScope( |
|||
key: this._drawerKey, |
|||
node: this._focusScopeNode, |
|||
child: this.widget.child) |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new ListTileTheme( |
|||
style: ListTileStyle.drawer, |
|||
child: this._buildDrawer(context)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 82ae9917639b741da9df1fe50aeeca67 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public class DrawerHeader : StatelessWidget { |
|||
public DrawerHeader( |
|||
Key key = null, |
|||
Decoration decoration = null, |
|||
EdgeInsets margin = null, |
|||
EdgeInsets padding = null, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
D.assert(child != null); |
|||
this.decoration = decoration; |
|||
this.margin = margin ?? EdgeInsets.only(bottom: 8.0); |
|||
this.padding = padding ?? EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0); |
|||
this.duration = duration ?? new TimeSpan(0, 0, 0, 0, 250); |
|||
this.curve = curve ?? Curves.fastOutSlowIn; |
|||
this.child = child; |
|||
} |
|||
|
|||
|
|||
public readonly Decoration decoration; |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
public readonly EdgeInsets margin; |
|||
|
|||
public readonly TimeSpan duration; |
|||
|
|||
public readonly Curve curve; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(MaterialDebug.debugCheckHasMaterial(context)); |
|||
ThemeData theme = Theme.of(context); |
|||
double statusBarHeight = MediaQuery.of(context).padding.top; |
|||
return new Container( |
|||
height: statusBarHeight + DrawerHeaderUtils._kDrawerHeaderHeight, |
|||
margin: this.margin, |
|||
decoration: new BoxDecoration( |
|||
border: new Border( |
|||
bottom: Divider.createBorderSide(context) |
|||
) |
|||
), |
|||
child: new AnimatedContainer( |
|||
padding: this.padding.add(EdgeInsets.only(top: statusBarHeight)), |
|||
decoration: this.decoration, |
|||
duration: this.duration, |
|||
curve: this.curve, |
|||
child: this.child == null |
|||
? null |
|||
: new DefaultTextStyle( |
|||
style: theme.textTheme.body2, |
|||
child: MediaQuery.removePadding( |
|||
context: context, |
|||
removeTop: true, |
|||
child: this.child) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b98e2be2eba264e28b3ca08fa93d0f2a |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public class ExpandIcon : StatefulWidget { |
|||
public ExpandIcon( |
|||
Key key = null, |
|||
bool isExpanded = false, |
|||
double size = 24.0, |
|||
ValueChanged<bool> onPressed = null, |
|||
EdgeInsets padding = null) : base(key: key) { |
|||
this.isExpanded = isExpanded; |
|||
this.size = size; |
|||
this.onPressed = onPressed; |
|||
this.padding = padding ?? EdgeInsets.all(8.0); |
|||
} |
|||
|
|||
public readonly bool isExpanded; |
|||
|
|||
public readonly double size; |
|||
|
|||
public readonly ValueChanged<bool> onPressed; |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
public override State createState() { |
|||
return new _ExpandIconState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _ExpandIconState : SingleTickerProviderStateMixin<ExpandIcon> { |
|||
AnimationController _controller; |
|||
Animation<double> _iconTurns; |
|||
|
|||
static readonly Animatable<double> _iconTurnTween = |
|||
new DoubleTween(begin: 0.0, end: 0.5).chain(new CurveTween(curve: Curves.fastOutSlowIn)); |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController(duration: ThemeUtils.kThemeAnimationDuration, vsync: this); |
|||
this._iconTurns = this._controller.drive(_iconTurnTween); |
|||
if (this.widget.isExpanded) { |
|||
this._controller.setValue(Math.PI); |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
ExpandIcon _oldWidget = (ExpandIcon) oldWidget; |
|||
if (this.widget.isExpanded != _oldWidget.isExpanded) { |
|||
if (this.widget.isExpanded) { |
|||
this._controller.forward(); |
|||
} |
|||
else { |
|||
this._controller.reverse(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void _handlePressed() { |
|||
if (this.widget.onPressed != null) { |
|||
this.widget.onPressed(this.widget.isExpanded); |
|||
} |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(MaterialDebug.debugCheckHasMaterial(context)); |
|||
ThemeData theme = Theme.of(context); |
|||
return new IconButton( |
|||
padding: this.widget.padding, |
|||
color: theme.brightness == Brightness.dark ? Colors.white54 : Colors.black54, |
|||
onPressed: this.widget.onPressed == null ? (VoidCallback) null : this._handlePressed, |
|||
icon: new RotationTransition( |
|||
turns: this._iconTurns, |
|||
child: new Icon(Icons.expand_more)) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e4ab856e0b8e94feabef78ecb303733b |
|||
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.widgets; |
|||
using UnityEngine.Networking; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
class _SaltedKey<S, V> : LocalKey { |
|||
public _SaltedKey( |
|||
S salt, |
|||
V value) { |
|||
this.salt = salt; |
|||
this.value = value; |
|||
} |
|||
|
|||
public readonly S salt; |
|||
|
|||
public readonly V value; |
|||
|
|||
public bool Equals(_SaltedKey<S, V> other) { |
|||
if (ReferenceEquals(null, other)) { |
|||
return false; |
|||
} |
|||
|
|||
if (ReferenceEquals(this, other)) { |
|||
return true; |
|||
} |
|||
|
|||
return other.salt.Equals(this.salt) |
|||
&& other.value.Equals(this.value); |
|||
} |
|||
|
|||
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((_SaltedKey<S, V>) obj); |
|||
} |
|||
|
|||
public static bool operator ==(_SaltedKey<S, V> left, _SaltedKey<S, V> right) { |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(_SaltedKey<S, V> left, _SaltedKey<S, V> right) { |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = this.salt.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.value.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
string saltString = this.salt is string ? "<\'" + this.salt + "\'>" : "<" + this.salt + ">"; |
|||
string valueString = this.value is string ? "<\'" + this.value + "\'>" : "<" + this.value + ">"; |
|||
return "[" + saltString + " " + valueString + "]"; |
|||
} |
|||
} |
|||
|
|||
public delegate void ExpansionPanelCallback(int panelIndex, bool isExpanded); |
|||
|
|||
public delegate Widget ExpansionPanelHeaderBuilder(BuildContext context, bool isExpanded); |
|||
|
|||
|
|||
public class ExpansionPanel { |
|||
public ExpansionPanel( |
|||
ExpansionPanelHeaderBuilder headerBuilder = null, |
|||
Widget body = null, |
|||
bool isExpanded = false) { |
|||
D.assert(headerBuilder != null); |
|||
D.assert(body != null); |
|||
this.headerBuilder = headerBuilder; |
|||
this.body = body; |
|||
this.isExpanded = isExpanded; |
|||
} |
|||
|
|||
public readonly ExpansionPanelHeaderBuilder headerBuilder; |
|||
|
|||
public readonly Widget body; |
|||
|
|||
public readonly bool isExpanded; |
|||
} |
|||
|
|||
|
|||
public class ExpansionPanelRadio : ExpansionPanel { |
|||
public ExpansionPanelRadio( |
|||
object value = null, |
|||
ExpansionPanelHeaderBuilder headerBuilder = null, |
|||
Widget body = null) : base(body: body, headerBuilder: headerBuilder) { |
|||
D.assert(headerBuilder != null); |
|||
D.assert(body != null); |
|||
D.assert(value != null); |
|||
this.value = value; |
|||
} |
|||
|
|||
public readonly object value; |
|||
} |
|||
|
|||
public class ExpansionPanelList : StatefulWidget { |
|||
public ExpansionPanelList( |
|||
Key key = null, |
|||
List<ExpansionPanel> children = null, |
|||
ExpansionPanelCallback expansionCallback = null, |
|||
TimeSpan? animationDuration = null) : base(key: key) { |
|||
this.children = children ?? new List<ExpansionPanel>(); |
|||
this.expansionCallback = expansionCallback; |
|||
this.animationDuration = animationDuration ?? Constants.kThemeChangeDuration; |
|||
this._allowOnlyOnePanelOpen = false; |
|||
this.initialOpenPanelValue = null; |
|||
} |
|||
|
|||
ExpansionPanelList( |
|||
Key key = null, |
|||
List<ExpansionPanel> children = null, |
|||
ExpansionPanelCallback expansionCallback = null, |
|||
TimeSpan? animationDuration = null, |
|||
object initialOpenPanelValue = null) : base(key: key){ |
|||
this.children = children ?? new List<ExpansionPanel>(); |
|||
this.expansionCallback = expansionCallback; |
|||
this.animationDuration = animationDuration ?? Constants.kThemeChangeDuration; |
|||
this._allowOnlyOnePanelOpen = true; |
|||
this.initialOpenPanelValue = initialOpenPanelValue; |
|||
} |
|||
|
|||
public static ExpansionPanelList radio( |
|||
Key key = null, |
|||
List<ExpansionPanelRadio> children = null, |
|||
ExpansionPanelCallback expansionCallback = null, |
|||
TimeSpan? animationDuration = null, |
|||
object initialOpenPanelValue = null) { |
|||
var radio = new ExpansionPanelList( |
|||
key: key, |
|||
children: new List<ExpansionPanel>(children), |
|||
expansionCallback: expansionCallback, |
|||
animationDuration: animationDuration, |
|||
initialOpenPanelValue: initialOpenPanelValue |
|||
); |
|||
return radio; |
|||
} |
|||
|
|||
public readonly List<ExpansionPanel> children; |
|||
|
|||
public readonly ExpansionPanelCallback expansionCallback; |
|||
|
|||
public readonly TimeSpan animationDuration; |
|||
|
|||
//todo xingwei.zhu: make them readonly
|
|||
public readonly bool _allowOnlyOnePanelOpen; |
|||
|
|||
public readonly object initialOpenPanelValue; |
|||
|
|||
public override State createState() { |
|||
return new _ExpansionPanelListState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _ExpansionPanelListState : State<ExpansionPanelList> { |
|||
ExpansionPanelRadio _currentOpenPanel; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
if (this.widget._allowOnlyOnePanelOpen) { |
|||
D.assert(this._allIdentifierUnique(), "All object identifiers are not unique!"); |
|||
foreach (ExpansionPanelRadio child in this.widget.children) { |
|||
if (this.widget.initialOpenPanelValue != null && |
|||
child.value == this.widget.initialOpenPanelValue) { |
|||
this._currentOpenPanel = child; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
ExpansionPanelList _oldWidget = (ExpansionPanelList) oldWidget; |
|||
base.didUpdateWidget(_oldWidget); |
|||
if (this.widget._allowOnlyOnePanelOpen) { |
|||
D.assert(this._allIdentifierUnique(), "All object identifiers are not unique!"); |
|||
foreach (ExpansionPanelRadio newChild in this.widget.children) { |
|||
if (this.widget.initialOpenPanelValue != null && |
|||
newChild.value == this.widget.initialOpenPanelValue) { |
|||
this._currentOpenPanel = newChild; |
|||
} |
|||
} |
|||
} |
|||
else if (_oldWidget._allowOnlyOnePanelOpen) { |
|||
this._currentOpenPanel = null; |
|||
} |
|||
} |
|||
|
|||
bool _allIdentifierUnique() { |
|||
Dictionary<object, bool> identifierMap = new Dictionary<object, bool>(); |
|||
foreach (ExpansionPanelRadio child in this.widget.children) { |
|||
identifierMap[child.value] = true; |
|||
} |
|||
|
|||
return identifierMap.Count == this.widget.children.Count; |
|||
} |
|||
|
|||
bool _isChildExpanded(int index) { |
|||
if (this.widget._allowOnlyOnePanelOpen) { |
|||
ExpansionPanelRadio radioWidget = (ExpansionPanelRadio) this.widget.children[index]; |
|||
return this._currentOpenPanel?.value == radioWidget.value; |
|||
} |
|||
|
|||
return this.widget.children[index].isExpanded; |
|||
} |
|||
|
|||
void _handlePressed(bool isExpanded, int index) { |
|||
if (this.widget.expansionCallback != null) { |
|||
this.widget.expansionCallback(index, isExpanded); |
|||
} |
|||
|
|||
if (this.widget._allowOnlyOnePanelOpen) { |
|||
ExpansionPanelRadio pressedChild = (ExpansionPanelRadio) this.widget.children[index]; |
|||
|
|||
for (int childIndex = 0; childIndex < this.widget.children.Count; childIndex++) { |
|||
ExpansionPanelRadio child = (ExpansionPanelRadio) this.widget.children[childIndex]; |
|||
if (this.widget.expansionCallback != null && childIndex != index && |
|||
child.value == this._currentOpenPanel?.value) { |
|||
this.widget.expansionCallback(childIndex, false); |
|||
} |
|||
} |
|||
|
|||
this._currentOpenPanel = isExpanded ? null : pressedChild; |
|||
} |
|||
|
|||
this.setState(() => { }); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<MergeableMaterialItem> items = new List<MergeableMaterialItem>(); |
|||
EdgeInsets kExpandedEdgeInsets = EdgeInsets.symmetric( |
|||
vertical: ExpansionPanelUtils._kPanelHeaderExpandedHeight - |
|||
ExpansionPanelUtils._kPanelHeaderCollapsedHeight); |
|||
|
|||
for (int index = 0; index < this.widget.children.Count; index++) { |
|||
int expandIndex = index; |
|||
if (this._isChildExpanded(index) && index != 0 && !this._isChildExpanded(index - 1)) { |
|||
items.Add(new MaterialGap( |
|||
key: new _SaltedKey<BuildContext, int>(context, index * 2 - 1))); |
|||
} |
|||
|
|||
ExpansionPanel child = this.widget.children[index]; |
|||
Row header = new Row( |
|||
children: new List<Widget> { |
|||
new Expanded( |
|||
child: new AnimatedContainer( |
|||
duration: this.widget.animationDuration, |
|||
curve: Curves.fastOutSlowIn, |
|||
margin: this._isChildExpanded(index) ? kExpandedEdgeInsets : EdgeInsets.zero, |
|||
child: new ConstrainedBox( |
|||
constraints: new BoxConstraints( |
|||
minHeight: ExpansionPanelUtils._kPanelHeaderCollapsedHeight), |
|||
child: child.headerBuilder( |
|||
context, this._isChildExpanded(index)) |
|||
) |
|||
) |
|||
), |
|||
new Container( |
|||
margin: EdgeInsets.fromLTRB(0, 0, 8, 0), |
|||
child: new ExpandIcon( |
|||
isExpanded: this._isChildExpanded(index), |
|||
padding: EdgeInsets.all(16.0), |
|||
onPressed: (bool isExpanded) => this._handlePressed(isExpanded, expandIndex) |
|||
) |
|||
) |
|||
} |
|||
); |
|||
|
|||
items.Add(new MaterialSlice( |
|||
key: new _SaltedKey<BuildContext, int>(context, index * 2), |
|||
child: new Column( |
|||
children: new List<Widget> { |
|||
header, |
|||
new AnimatedCrossFade( |
|||
firstChild: new Container(height: 0.0), |
|||
secondChild: child.body, |
|||
firstCurve: new Interval(0.0, 0.6, curve: Curves.fastOutSlowIn), |
|||
secondCurve: new Interval(0.4, 1.0, curve: Curves.fastOutSlowIn), |
|||
sizeCurve: Curves.fastOutSlowIn, |
|||
crossFadeState: this._isChildExpanded(index) |
|||
? CrossFadeState.showSecond |
|||
: CrossFadeState.showFirst, |
|||
duration: this.widget.animationDuration |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
|
|||
if (this._isChildExpanded(index) && index != this.widget.children.Count - 1) { |
|||
items.Add(new MaterialGap( |
|||
key: new _SaltedKey<BuildContext, int>(context, index * 2 + 1))); |
|||
} |
|||
} |
|||
|
|||
return new MergeableMaterial( |
|||
hasDividers: true, |
|||
children: items); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: dcaf0d752807146868207f41db41ccb1 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public class GridTile : StatelessWidget { |
|||
public GridTile( |
|||
Key key = null, |
|||
Widget header = null, |
|||
Widget footer = null, |
|||
Widget child = null) : base(key: key) { |
|||
D.assert(child != null); |
|||
this.header = header; |
|||
this.footer = footer; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly Widget header; |
|||
|
|||
public readonly Widget footer; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
if (this.header == null && this.footer == null) { |
|||
return this.child; |
|||
} |
|||
|
|||
List<Widget> children = new List<Widget> { |
|||
Positioned.fill( |
|||
child: this.child) |
|||
}; |
|||
if (this.header != null) { |
|||
children.Add(new Positioned( |
|||
top: 0.0, |
|||
left: 0.0, |
|||
right: 0.0, |
|||
child: this.header)); |
|||
} |
|||
|
|||
if (this.footer != null) { |
|||
children.Add(new Positioned( |
|||
left: 0.0, |
|||
bottom: 0.0, |
|||
right: 0.0, |
|||
child: this.footer)); |
|||
} |
|||
|
|||
return new Stack( |
|||
children: children); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 8613dcab63f30445c80e76df18408797 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: edff6e5006499451b804753d07e8133d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public static class Icons { |
|||
public static IconData expand_more = new IconData(0xe5cf, fontFamily: "Material Icons"); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2507054e4ed9a4d9682f5453bd9e6061 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public enum ListTileStyle { |
|||
list, |
|||
drawer |
|||
} |
|||
|
|||
public class ListTileTheme : InheritedWidget { |
|||
public ListTileTheme( |
|||
Key key = null, |
|||
bool dense = false, |
|||
ListTileStyle style = ListTileStyle.list, |
|||
Color selectedColor = null, |
|||
Color iconColor = null, |
|||
Color textColor = null, |
|||
EdgeInsets contentPadding = null, |
|||
Widget child = null) : base(key: key, child: child) { |
|||
this.dense = dense; |
|||
this.style = style; |
|||
this.selectedColor = selectedColor; |
|||
this.iconColor = iconColor; |
|||
this.textColor = textColor; |
|||
this.contentPadding = contentPadding; |
|||
} |
|||
|
|||
public static Widget merge( |
|||
Key key = null, |
|||
bool? dense = null, |
|||
ListTileStyle? style = null, |
|||
Color selectedColor = null, |
|||
Color iconColor = null, |
|||
Color textColor = null, |
|||
EdgeInsets contentPadding = null, |
|||
Widget child = null) { |
|||
D.assert(child != null); |
|||
return new Builder( |
|||
builder: (BuildContext context) => { |
|||
ListTileTheme parent = of(context); |
|||
return new ListTileTheme( |
|||
key: key, |
|||
dense: dense ?? parent.dense, |
|||
style: style ?? parent.style, |
|||
selectedColor: selectedColor ?? parent.selectedColor, |
|||
iconColor: iconColor ?? parent.iconColor, |
|||
textColor: textColor ?? parent.textColor, |
|||
contentPadding: contentPadding ?? parent.contentPadding, |
|||
child: child); |
|||
} |
|||
); |
|||
} |
|||
|
|||
public readonly bool dense; |
|||
|
|||
public readonly ListTileStyle style; |
|||
|
|||
public readonly Color selectedColor; |
|||
|
|||
public readonly Color iconColor; |
|||
|
|||
public readonly Color textColor; |
|||
|
|||
public readonly EdgeInsets contentPadding; |
|||
|
|||
public static ListTileTheme of(BuildContext context) { |
|||
ListTileTheme result = (ListTileTheme) context.inheritFromWidgetOfExactType(typeof(ListTileTheme)); |
|||
return result ?? new ListTileTheme(); |
|||
} |
|||
|
|||
public override bool updateShouldNotify(InheritedWidget oldWidget) { |
|||
ListTileTheme _oldWidget = (ListTileTheme) oldWidget; |
|||
return this.dense != _oldWidget.dense || |
|||
this.style != _oldWidget.style || |
|||
this.selectedColor != _oldWidget.selectedColor || |
|||
this.iconColor != _oldWidget.iconColor || |
|||
this.textColor != _oldWidget.textColor || |
|||
this.contentPadding != _oldWidget.contentPadding; |
|||
} |
|||
} |
|||
|
|||
public enum ListTileControlAffinity { |
|||
leading, |
|||
trailing, |
|||
platform |
|||
} |
|||
|
|||
public class ListTile : StatelessWidget { |
|||
public ListTile( |
|||
Key key = null, |
|||
Widget leading = null, |
|||
Widget title = null, |
|||
Widget subtitle = null, |
|||
Widget trailing = null, |
|||
bool isThreeLine = false, |
|||
bool? dense = null, |
|||
EdgeInsets contentPadding = null, |
|||
bool enabled = true, |
|||
GestureTapCallback onTap = null, |
|||
GestureLongPressCallback onLongPress = null, |
|||
bool selected = false |
|||
) : base(key: key) { |
|||
D.assert(!isThreeLine || subtitle != null); |
|||
this.leading = leading; |
|||
this.title = title; |
|||
this.subtitle = subtitle; |
|||
this.trailing = trailing; |
|||
this.isThreeLine = isThreeLine; |
|||
this.dense = dense; |
|||
this.contentPadding = contentPadding; |
|||
this.enabled = enabled; |
|||
this.onTap = onTap; |
|||
this.onLongPress = onLongPress; |
|||
this.selected = selected; |
|||
} |
|||
|
|||
public readonly Widget leading; |
|||
|
|||
public readonly Widget title; |
|||
|
|||
public readonly Widget subtitle; |
|||
|
|||
public readonly Widget trailing; |
|||
|
|||
public readonly bool isThreeLine; |
|||
|
|||
public readonly bool? dense; |
|||
|
|||
public readonly EdgeInsets contentPadding; |
|||
|
|||
public readonly bool enabled; |
|||
|
|||
public readonly GestureTapCallback onTap; |
|||
|
|||
public readonly GestureLongPressCallback onLongPress; |
|||
|
|||
public readonly bool selected; |
|||
|
|||
Color _iconColor(ThemeData theme, ListTileTheme tileTheme) { |
|||
if (!this.enabled) { |
|||
return theme.disabledColor; |
|||
} |
|||
|
|||
if (this.selected && tileTheme?.selectedColor != null) { |
|||
return tileTheme.selectedColor; |
|||
} |
|||
|
|||
if (!this.selected && tileTheme?.iconColor != null) { |
|||
return tileTheme.iconColor; |
|||
} |
|||
|
|||
switch (theme.brightness) { |
|||
case Brightness.light: |
|||
return this.selected ? theme.primaryColor : Colors.black45; |
|||
case Brightness.dark: |
|||
return this.selected ? theme.accentColor : null; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
Color _textColor(ThemeData theme, ListTileTheme tileTheme, Color defaultColor) { |
|||
if (!this.enabled) { |
|||
return theme.disabledColor; |
|||
} |
|||
|
|||
if (this.selected && tileTheme?.selectedColor != null) { |
|||
return tileTheme.selectedColor; |
|||
} |
|||
|
|||
if (!this.selected && tileTheme?.textColor != null) { |
|||
return tileTheme.textColor; |
|||
} |
|||
|
|||
if (this.selected) { |
|||
switch (theme.brightness) { |
|||
case Brightness.light: |
|||
return theme.primaryColor; |
|||
case Brightness.dark: |
|||
return theme.accentColor; |
|||
} |
|||
} |
|||
|
|||
return defaultColor; |
|||
} |
|||
|
|||
bool _isDenseLayout(ListTileTheme tileTheme) { |
|||
return this.dense != null ? this.dense ?? false : (tileTheme?.dense ?? false); |
|||
} |
|||
|
|||
TextStyle _titleTextStyle(ThemeData theme, ListTileTheme tileTheme) { |
|||
TextStyle style = null; |
|||
if (tileTheme != null) { |
|||
switch (tileTheme.style) { |
|||
case ListTileStyle.drawer: |
|||
style = theme.textTheme.body2; |
|||
break; |
|||
case ListTileStyle.list: |
|||
style = theme.textTheme.subhead; |
|||
break; |
|||
} |
|||
} |
|||
else { |
|||
style = theme.textTheme.subhead; |
|||
} |
|||
|
|||
Color color = this._textColor(theme, tileTheme, style.color); |
|||
return this._isDenseLayout(tileTheme) |
|||
? style.copyWith(fontSize: 13.0, color: color) |
|||
: style.copyWith(color: color); |
|||
} |
|||
|
|||
TextStyle _subtitleTextStyle(ThemeData theme, ListTileTheme tileTheme) { |
|||
TextStyle style = theme.textTheme.body1; |
|||
Color color = this._textColor(theme, tileTheme, theme.textTheme.caption.color); |
|||
return this._isDenseLayout(tileTheme) |
|||
? style.copyWith(color: color, fontSize: 12.0) |
|||
: style.copyWith(color: color); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(MaterialDebug.debugCheckHasMaterial(context)); |
|||
ThemeData theme = Theme.of(context); |
|||
ListTileTheme tileTheme = ListTileTheme.of(context); |
|||
|
|||
IconThemeData iconThemeData = null; |
|||
if (this.leading != null || this.trailing != null) { |
|||
iconThemeData = new IconThemeData(color: this._iconColor(theme, tileTheme)); |
|||
} |
|||
|
|||
Widget leadingIcon = null; |
|||
if (this.leading != null) { |
|||
leadingIcon = IconTheme.merge( |
|||
data: iconThemeData, |
|||
child: this.leading); |
|||
} |
|||
|
|||
TextStyle titleStyle = this._titleTextStyle(theme, tileTheme); |
|||
Widget titleText = new AnimatedDefaultTextStyle( |
|||
style: titleStyle, |
|||
duration: Constants.kThemeChangeDuration, |
|||
child: this.title ?? new SizedBox()); |
|||
|
|||
Widget subtitleText = null; |
|||
TextStyle subtitleStyle = null; |
|||
if (this.subtitle != null) { |
|||
subtitleStyle = this._subtitleTextStyle(theme, tileTheme); |
|||
subtitleText = new AnimatedDefaultTextStyle( |
|||
style: subtitleStyle, |
|||
duration: Constants.kThemeChangeDuration, |
|||
child: this.subtitle); |
|||
} |
|||
|
|||
Widget trailingIcon = null; |
|||
if (this.trailing != null) { |
|||
trailingIcon = IconTheme.merge( |
|||
data: iconThemeData, |
|||
child: this.trailing); |
|||
} |
|||
|
|||
EdgeInsets _defaultContentPadding = EdgeInsets.symmetric(horizontal: 16.0); |
|||
EdgeInsets resolvedContentPadding = _defaultContentPadding; |
|||
|
|||
return new InkWell( |
|||
onTap: this.enabled ? this.onTap : null, |
|||
onLongPress: this.enabled ? this.onLongPress : null, |
|||
child: new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
mininum: resolvedContentPadding, |
|||
child: new _ListTile( |
|||
leading: leadingIcon, |
|||
title: titleText, |
|||
subtitle: subtitleText, |
|||
trailing: trailingIcon, |
|||
isDense: this._isDenseLayout(tileTheme), |
|||
isThreeLine: this.isThreeLine, |
|||
titleBaselineType: titleStyle.textBaseline, |
|||
subtitleBaselineType: subtitleStyle?.textBaseline |
|||
)) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public enum _ListTileSlot { |
|||
leading, |
|||
title, |
|||
subtitle, |
|||
trailing |
|||
} |
|||
|
|||
public class _ListTile : RenderObjectWidget { |
|||
public _ListTile( |
|||
Key key = null, |
|||
Widget leading = null, |
|||
Widget title = null, |
|||
Widget subtitle = null, |
|||
Widget trailing = null, |
|||
bool? isThreeLine = null, |
|||
bool? isDense = null, |
|||
TextBaseline? titleBaselineType = null, |
|||
TextBaseline? subtitleBaselineType = null) : base(key: key) { |
|||
D.assert(isThreeLine != null); |
|||
D.assert(isDense != null); |
|||
D.assert(titleBaselineType != null); |
|||
this.leading = leading; |
|||
this.title = title; |
|||
this.subtitle = subtitle; |
|||
this.trailing = trailing; |
|||
this.isThreeLine = isThreeLine ?? false; |
|||
this.isDense = isDense ?? false; |
|||
this.titleBaselineType = titleBaselineType ?? TextBaseline.alphabetic; |
|||
this.subtitleBaselineType = subtitleBaselineType; |
|||
} |
|||
|
|||
public readonly Widget leading; |
|||
|
|||
public readonly Widget title; |
|||
|
|||
public readonly Widget subtitle; |
|||
|
|||
public readonly Widget trailing; |
|||
|
|||
public readonly bool isThreeLine; |
|||
|
|||
public readonly bool isDense; |
|||
|
|||
public readonly TextBaseline titleBaselineType; |
|||
|
|||
public readonly TextBaseline? subtitleBaselineType; |
|||
|
|||
public override Element createElement() { |
|||
return new _ListTileElement(this); |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new _RenderListTile( |
|||
); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _ListTileElement : RenderObjectElement { |
|||
public _ListTileElement(RenderObjectWidget widget) : base(widget) { |
|||
} |
|||
|
|||
readonly Dictionary<_ListTileSlot, Element> slotToChild = new Dictionary<_ListTileSlot, Element>(); |
|||
readonly Dictionary<Element, _ListTileSlot> childToSlot = new Dictionary<Element, _ListTileSlot>(); |
|||
|
|||
new public _ListTile widget { |
|||
get { return (_ListTile) base.widget; } |
|||
} |
|||
|
|||
new public _RenderListTile renderObject { |
|||
get { return (_RenderListTile) base.renderObject; } |
|||
} |
|||
|
|||
public override void visitChildren(ElementVisitor visitor) { |
|||
foreach (var element in this.slotToChild.Values) { |
|||
visitor(element); |
|||
} |
|||
} |
|||
|
|||
protected override void forgetChild(Element child) { |
|||
D.assert(this.slotToChild.Values.Contains(child)); |
|||
D.assert(this.childToSlot.Keys.Contains(child)); |
|||
_ListTileSlot slot = this.childToSlot[child]; |
|||
this.childToSlot.Remove(child); |
|||
this.slotToChild.Remove(slot); |
|||
} |
|||
|
|||
void _mountChild(Widget widget, _ListTileSlot slot) { |
|||
Element oldChild = this.slotToChild[slot]; |
|||
Element newChild = this.updateChild(oldChild, widget, slot); |
|||
if (oldChild != null) { |
|||
this.slotToChild.Remove(slot); |
|||
this.childToSlot.Remove(oldChild); |
|||
} |
|||
|
|||
if (newChild != null) { |
|||
this.slotToChild[slot] = newChild; |
|||
this.childToSlot[newChild] = slot; |
|||
} |
|||
} |
|||
|
|||
public override void mount(Element parent, object newSlot) { |
|||
base.mount(parent, newSlot); |
|||
this._mountChild(this.widget.leading, _ListTileSlot.leading); |
|||
this._mountChild(this.widget.title, _ListTileSlot.title); |
|||
this._mountChild(this.widget.subtitle, _ListTileSlot.subtitle); |
|||
this._mountChild(this.widget.trailing, _ListTileSlot.trailing); |
|||
} |
|||
|
|||
void _updateChild(Widget widget, _ListTileSlot slot) { |
|||
Element oldChild = this.slotToChild[slot]; |
|||
Element newChild = this.updateChild(oldChild, widget, slot); |
|||
if (oldChild != null) { |
|||
this.childToSlot.Remove(oldChild); |
|||
this.slotToChild.Remove(slot); |
|||
} |
|||
|
|||
if (newChild != null) { |
|||
this.slotToChild[slot] = newChild; |
|||
this.childToSlot[newChild] = slot; |
|||
} |
|||
} |
|||
|
|||
public override void update(Widget newWidget) { |
|||
base.update(newWidget); |
|||
D.assert(this.widget == newWidget); |
|||
this._updateChild(this.widget.leading, _ListTileSlot.leading); |
|||
this._updateChild(this.widget.title, _ListTileSlot.title); |
|||
this._updateChild(this.widget.subtitle, _ListTileSlot.subtitle); |
|||
this._updateChild(this.widget.trailing, _ListTileSlot.trailing); |
|||
} |
|||
|
|||
void _updateRenderObject(RenderObject child, _ListTileSlot slot) { |
|||
switch (slot) { |
|||
case _ListTileSlot.leading: |
|||
this.renderObject.leading = (RenderBox) child; |
|||
break; |
|||
case _ListTileSlot.title: |
|||
this.renderObject.title = (RenderBox) child; |
|||
break; |
|||
case _ListTileSlot.subtitle: |
|||
this.renderObject.subtitle = (RenderBox) child; |
|||
break; |
|||
case _ListTileSlot.trailing: |
|||
this.renderObject.trailing = (RenderBox) child; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
protected override void insertChildRenderObject(RenderObject child, object slotValue) { |
|||
D.assert(child is RenderBox); |
|||
D.assert(slotValue is _ListTileSlot); |
|||
_ListTileSlot slot = (_ListTileSlot) slotValue; |
|||
this._updateRenderObject(child, slot); |
|||
D.assert(this.renderObject.childToSlot.Keys.Contains(child)); |
|||
D.assert(this.renderObject.slotToChild.Keys.Contains(slot)); |
|||
} |
|||
|
|||
protected override void removeChildRenderObject(RenderObject child) { |
|||
D.assert(child is RenderBox); |
|||
D.assert(this.renderObject.childToSlot.Keys.Contains(child)); |
|||
_ListTileSlot slot = this.renderObject.childToSlot[(RenderBox) child]; |
|||
this._updateRenderObject(null, this.renderObject.childToSlot[(RenderBox) child]); |
|||
D.assert(!this.renderObject.childToSlot.Keys.Contains(child)); |
|||
D.assert(!this.renderObject.slotToChild.Keys.Contains(slot)); |
|||
} |
|||
|
|||
protected override void moveChildRenderObject(RenderObject child, object slotValue) { |
|||
D.assert(false, "not reachable"); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _RenderListTile : RenderBox { |
|||
public _RenderListTile( |
|||
bool? isDense = null, |
|||
bool? isThreeLine = null, |
|||
TextBaseline? titleBaselineType = null, |
|||
TextBaseline? subtitleBaselineType = null) { |
|||
D.assert(isDense != null); |
|||
D.assert(isThreeLine != null); |
|||
D.assert(titleBaselineType != null); |
|||
} |
|||
|
|||
const double _minLeadingWidth = 40.0; |
|||
|
|||
const double _horizonalTitleGrap = 16.0; |
|||
|
|||
const double _minVerticalPadding = 4.0; |
|||
|
|||
public readonly Dictionary<_ListTileSlot, RenderBox> slotToChild = new Dictionary<_ListTileSlot, RenderBox>(); |
|||
public readonly Dictionary<RenderBox, _ListTileSlot> childToSlot = new Dictionary<RenderBox, _ListTileSlot>(); |
|||
|
|||
RenderBox _updateChild(RenderBox oldChild, RenderBox newChild, _ListTileSlot slot) { |
|||
if (oldChild != null) { |
|||
this.dropChild(oldChild); |
|||
this.childToSlot.Remove(oldChild); |
|||
this.slotToChild.Remove(slot); |
|||
} |
|||
|
|||
if (newChild != null) { |
|||
this.childToSlot[newChild] = slot; |
|||
this.slotToChild[slot] = newChild; |
|||
this.adoptChild(newChild); |
|||
} |
|||
|
|||
return newChild; |
|||
} |
|||
|
|||
RenderBox _leading; |
|||
|
|||
public RenderBox leading { |
|||
get { return this._leading; } |
|||
set { this._leading = this._updateChild(this._leading, value, _ListTileSlot.leading); } |
|||
} |
|||
|
|||
RenderBox _title; |
|||
|
|||
public RenderBox title { |
|||
get { return this._title; } |
|||
set { this._title = this._updateChild(this._title, value, _ListTileSlot.title); } |
|||
} |
|||
|
|||
RenderBox _subtitle; |
|||
|
|||
public RenderBox subtitle { |
|||
get { return this._subtitle; } |
|||
set { this._subtitle = this._updateChild(this._subtitle, value, _ListTileSlot.subtitle); } |
|||
} |
|||
|
|||
RenderBox _trailing; |
|||
|
|||
public RenderBox trailing { |
|||
get { return this._trailing; } |
|||
set { this._trailing = this._updateChild(this._trailing, value, _ListTileSlot.trailing); } |
|||
} |
|||
|
|||
List<RenderObject> _children { |
|||
get { |
|||
List<RenderObject> ret = new List<RenderObject>(); |
|||
if (this.leading != null) { |
|||
ret.Add(this.leading); |
|||
} |
|||
|
|||
if (this.title != null) { |
|||
ret.Add(this.title); |
|||
} |
|||
|
|||
if (this.subtitle != null) { |
|||
ret.Add(this.subtitle); |
|||
} |
|||
|
|||
if (this.trailing != null) { |
|||
ret.Add(this.trailing); |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
public bool isDense { |
|||
get { return this._isDense; } |
|||
set { |
|||
if (this._isDense == value) { |
|||
return; |
|||
} |
|||
|
|||
this._isDense = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
bool _isDense; |
|||
|
|||
public bool isThreeLine { |
|||
get { return this._isThreeLine; } |
|||
set { |
|||
if (this._isThreeLine == value) { |
|||
return; |
|||
} |
|||
|
|||
this._isThreeLine = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
bool _isThreeLine; |
|||
|
|||
public TextBaseline titleBaseLineType { |
|||
get { return this._titleBaselineType; } |
|||
set { |
|||
if (this._titleBaselineType == value) { |
|||
return; |
|||
} |
|||
|
|||
this._titleBaselineType = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
TextBaseline _titleBaselineType; |
|||
|
|||
public TextBaseline subtitleBaselineType { |
|||
get { return this._subtitleBaselineType; } |
|||
set { |
|||
if (this._subtitleBaselineType == value) { |
|||
return; |
|||
} |
|||
|
|||
this._subtitleBaselineType = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
TextBaseline _subtitleBaselineType; |
|||
|
|||
public override void attach(object owner) { |
|||
base.attach(owner); |
|||
foreach (RenderBox child in this._children) { |
|||
child.attach(owner); |
|||
} |
|||
} |
|||
|
|||
public override void detach() { |
|||
base.detach(); |
|||
foreach (RenderBox child in this._children) { |
|||
child.detach(); |
|||
} |
|||
} |
|||
|
|||
public override void redepthChildren() { |
|||
foreach (var child in this._children) { |
|||
this.redepthChild(child); |
|||
} |
|||
} |
|||
|
|||
public override void visitChildren(RenderObjectVisitor visitor) { |
|||
foreach (var child in this._children) { |
|||
visitor(child); |
|||
} |
|||
} |
|||
|
|||
public override List<DiagnosticsNode> debugDescribeChildren() { |
|||
List<DiagnosticsNode> value = new List<DiagnosticsNode>(); |
|||
|
|||
void add(RenderBox child, string name) { |
|||
if (child != null) { |
|||
value.Add(child.toDiagnosticsNode(name: name)); |
|||
} |
|||
} |
|||
|
|||
add(this.leading, "leading"); |
|||
add(this.title, "title"); |
|||
add(this.subtitle, "subtitle"); |
|||
add(this.trailing, "trailing"); |
|||
return value; |
|||
} |
|||
|
|||
public new bool sizedByParent { |
|||
get { return false; } |
|||
} |
|||
|
|||
static double _minWidth(RenderBox box, double height) { |
|||
return box == null ? 0.0 : box.getMinIntrinsicWidth(height); |
|||
} |
|||
|
|||
static double _maxWidth(RenderBox box, double height) { |
|||
return box == null ? 0.0 : box.getMaxIntrinsicWidth(height); |
|||
} |
|||
|
|||
protected override double computeMinIntrinsicWidth(double height) { |
|||
double leadingWidth = this.leading != null |
|||
? Math.Max(this.leading.getMinIntrinsicWidth(height), _minLeadingWidth) + _horizonalTitleGrap |
|||
: 0.0; |
|||
return leadingWidth + Math.Max(_minWidth(this.title, height), _minWidth(this.subtitle, height)) + |
|||
_maxWidth(this.trailing, height); |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicWidth(double height) { |
|||
double leadingWidth = this.leading != null |
|||
? Math.Max(this.leading.getMinIntrinsicWidth(height), _minLeadingWidth) + _horizonalTitleGrap |
|||
: 0.0; |
|||
return leadingWidth + Math.Max(_maxWidth(this.title, height), _maxWidth(this.subtitle, height)) + |
|||
_maxWidth(this.trailing, height); |
|||
} |
|||
|
|||
double _defaultTileHeight { |
|||
get { |
|||
bool hasSubtitle = this.subtitle != null; |
|||
bool isTwoLine = !this.isThreeLine && hasSubtitle; |
|||
bool isOneLine = !this.isThreeLine && !hasSubtitle; |
|||
|
|||
if (isOneLine) { |
|||
return this.isDense ? 48.0 : 56.0; |
|||
} |
|||
|
|||
if (isTwoLine) { |
|||
return this.isDense ? 64.0 : 72.0; |
|||
} |
|||
|
|||
return this.isDense ? 76.0 : 88.0; |
|||
} |
|||
} |
|||
|
|||
protected override double computeMinIntrinsicHeight(double width) { |
|||
return Math.Max( |
|||
this._defaultTileHeight, |
|||
this.title.getMinIntrinsicHeight(width) + this.subtitle?.getMinIntrinsicHeight(width) ?? 0.0); |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicHeight(double width) { |
|||
return this.computeMinIntrinsicHeight(width); |
|||
} |
|||
|
|||
protected override double? computeDistanceToActualBaseline(TextBaseline baseline) { |
|||
D.assert(this.title != null); |
|||
BoxParentData parentData = (BoxParentData) this.title.parentData; |
|||
return parentData.offset.dy + this.title.getDistanceToActualBaseline(baseline); |
|||
} |
|||
|
|||
static double _boxBaseline(RenderBox box, TextBaseline baseline) { |
|||
return box.getDistanceToBaseline(baseline) ?? 0.0; |
|||
} |
|||
|
|||
static Size _layoutBox(RenderBox box, BoxConstraints constraints) { |
|||
if (box == null) { |
|||
return Size.zero; |
|||
} |
|||
|
|||
box.layout(constraints, parentUsesSize: true); |
|||
return box.size; |
|||
} |
|||
|
|||
static void _positionBox(RenderBox box, Offset offset) { |
|||
BoxParentData parentData = (BoxParentData) box.parentData; |
|||
parentData.offset = offset; |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
bool hasLeading = this.leading != null; |
|||
bool hasSubtitle = this.subtitle != null; |
|||
bool hasTrailing = this.trailing != null; |
|||
bool isTwoLine = !this.isThreeLine && hasSubtitle; |
|||
bool isOneLine = !this.isThreeLine && !hasSubtitle; |
|||
BoxConstraints looseConstraints = this.constraints.loosen(); |
|||
|
|||
double tileWidth = looseConstraints.maxWidth; |
|||
Size leadingSize = _layoutBox(this.leading, looseConstraints); |
|||
Size trailingSize = _layoutBox(this.trailing, looseConstraints); |
|||
|
|||
double titleStart = hasLeading ? Math.Max(_minLeadingWidth, leadingSize.width) + _horizonalTitleGrap : 0.0; |
|||
BoxConstraints textConstraints = looseConstraints.tighten( |
|||
width: tileWidth - titleStart - (hasTrailing ? trailingSize.width + _horizonalTitleGrap : 0.0)); |
|||
Size titleSize = _layoutBox(this.title, textConstraints); |
|||
Size subtitleSize = _layoutBox(this.subtitle, textConstraints); |
|||
|
|||
double titleBaseline = 0.0; |
|||
double subtitleBaseline = 0.0; |
|||
if (isTwoLine) { |
|||
titleBaseline = this.isDense ? 28.0 : 32.0; |
|||
subtitleBaseline = this.isDense ? 48.0 : 52.0; |
|||
} |
|||
else if (this.isThreeLine) { |
|||
titleBaseline = this.isDense ? 22.0 : 28.0; |
|||
subtitleBaseline = this.isDense ? 42.0 : 48.0; |
|||
} |
|||
else { |
|||
D.assert(isOneLine); |
|||
} |
|||
|
|||
double tileHeight = 0.0; |
|||
double titleY = 0.0; |
|||
double subtitleY = 0.0; |
|||
if (!hasSubtitle) { |
|||
tileHeight = Math.Max(this._defaultTileHeight, titleSize.height + 2.0 * _minVerticalPadding); |
|||
titleY = (tileHeight - titleSize.height) / 2.0; |
|||
} |
|||
else { |
|||
titleY = titleBaseline - _boxBaseline(this.title, this.titleBaseLineType); |
|||
subtitleY = subtitleBaseline - _boxBaseline(this.subtitle, this.subtitleBaselineType); |
|||
tileHeight = this._defaultTileHeight; |
|||
|
|||
double titleOverlap = titleY + titleSize.height - subtitleY; |
|||
if (titleOverlap > 0.0) { |
|||
titleY -= titleOverlap / 2.0; |
|||
subtitleY += titleOverlap / 2.0; |
|||
} |
|||
|
|||
if (titleY < _minVerticalPadding || |
|||
(subtitleY + subtitleSize.height + _minVerticalPadding) > tileHeight) { |
|||
tileHeight = titleSize.height + subtitleSize.height + 2.0 * _minVerticalPadding; |
|||
titleY = _minVerticalPadding; |
|||
subtitleY = titleSize.height + _minVerticalPadding; |
|||
} |
|||
} |
|||
|
|||
double leadingY = (tileHeight - leadingSize.height) / 2.0; |
|||
double trailingY = (tileHeight - trailingSize.height) / 2.0; |
|||
|
|||
if (hasLeading) { |
|||
_positionBox(this.leading, new Offset(0.0, leadingY)); |
|||
} |
|||
|
|||
_positionBox(this.title, new Offset(titleStart, titleY)); |
|||
if (hasSubtitle) { |
|||
_positionBox(this.subtitle, new Offset(titleStart, subtitleY)); |
|||
} |
|||
|
|||
if (hasTrailing) { |
|||
_positionBox(this.trailing, new Offset(tileWidth - trailingSize.width, trailingY)); |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(new Size(tileWidth, tileHeight)); |
|||
D.assert(this.size.width == this.constraints.constrainWidth(tileWidth)); |
|||
D.assert(this.size.height == this.constraints.constrainHeight(tileHeight)); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
void doPaint(RenderBox child) { |
|||
if (child != null) { |
|||
BoxParentData parentData = (BoxParentData) child.parentData; |
|||
context.paintChild(child, parentData.offset + offset); |
|||
} |
|||
} |
|||
|
|||
doPaint(this.leading); |
|||
doPaint(this.title); |
|||
doPaint(this.subtitle); |
|||
doPaint(this.trailing); |
|||
} |
|||
|
|||
protected override bool hitTestSelf(Offset position) { |
|||
return true; |
|||
} |
|||
|
|||
protected override bool hitTestChildren(HitTestResult result, Offset position) { |
|||
D.assert(position != null); |
|||
foreach (RenderBox child in this._children) { |
|||
BoxParentData parentData = (BoxParentData) child.parentData; |
|||
if (child.hitTest(result, position: position - parentData.offset)) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b3757b5d4b8f740c0a93dcb13e9d8eda |
|||
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.utils; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public abstract class MergeableMaterialItem { |
|||
public MergeableMaterialItem( |
|||
LocalKey key) { |
|||
D.assert(key != null); |
|||
this.key = key; |
|||
} |
|||
|
|||
public readonly LocalKey key; |
|||
} |
|||
|
|||
public class MaterialSlice : MergeableMaterialItem { |
|||
public MaterialSlice( |
|||
LocalKey key = null, |
|||
Widget child = null) : base(key: key) { |
|||
D.assert(key != null); |
|||
D.assert(child != null); |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override string ToString() { |
|||
return "MergeableSlice(key: " + this.key + ", child: " + this.child + ")"; |
|||
} |
|||
} |
|||
|
|||
public class MaterialGap : MergeableMaterialItem { |
|||
public MaterialGap( |
|||
LocalKey key = null, |
|||
double size = 16.0) : base(key: key) { |
|||
D.assert(key != null); |
|||
this.size = size; |
|||
} |
|||
|
|||
public readonly double size; |
|||
|
|||
public override string ToString() { |
|||
return "MaterialGap(key: " + this.key + ", child: " + this.size + ")"; |
|||
} |
|||
} |
|||
|
|||
|
|||
public class MergeableMaterial : StatefulWidget { |
|||
public MergeableMaterial( |
|||
Key key = null, |
|||
Axis mainAxis = Axis.vertical, |
|||
int elevation = 2, |
|||
bool hasDividers = false, |
|||
List<MergeableMaterialItem> children = null) : base(key: key) { |
|||
this.mainAxis = mainAxis; |
|||
this.elevation = elevation; |
|||
this.hasDividers = hasDividers; |
|||
this.children = children ?? new List<MergeableMaterialItem>(); |
|||
} |
|||
|
|||
public readonly List<MergeableMaterialItem> children; |
|||
|
|||
public readonly Axis mainAxis; |
|||
|
|||
public readonly int elevation; |
|||
|
|||
public readonly bool hasDividers; |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<Axis>("mainAxis", this.mainAxis)); |
|||
properties.add(new DoubleProperty("elevation", this.elevation)); |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _MergeableMaterialState(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _AnimationTuple { |
|||
public _AnimationTuple( |
|||
AnimationController controller = null, |
|||
CurvedAnimation startAnimation = null, |
|||
CurvedAnimation endAnimation = null, |
|||
CurvedAnimation gapAnimation = null, |
|||
double gapStart = 0.0) { |
|||
this.controller = controller; |
|||
this.startAnimation = startAnimation; |
|||
this.endAnimation = endAnimation; |
|||
this.gapAnimation = gapAnimation; |
|||
this.gapStart = gapStart; |
|||
} |
|||
|
|||
public readonly AnimationController controller; |
|||
|
|||
public readonly CurvedAnimation startAnimation; |
|||
|
|||
public readonly CurvedAnimation endAnimation; |
|||
|
|||
public readonly CurvedAnimation gapAnimation; |
|||
|
|||
public double gapStart; |
|||
} |
|||
|
|||
|
|||
public class _MergeableMaterialState : TickerProviderStateMixin<MergeableMaterial> { |
|||
List<MergeableMaterialItem> _children; |
|||
|
|||
public readonly Dictionary<LocalKey, _AnimationTuple> _animationTuples = |
|||
new Dictionary<LocalKey, _AnimationTuple>(); |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._children = new List<MergeableMaterialItem>(); |
|||
this._children.AddRange(this.widget.children); |
|||
|
|||
for (int i = 0; i < this._children.Count; i += 1) { |
|||
if (this._children[i] is MaterialGap) { |
|||
this._initGap((MaterialGap) this._children[i]); |
|||
this._animationTuples[this._children[i].key].controller.setValue(1.0); |
|||
} |
|||
} |
|||
|
|||
D.assert(this._debugGapsAreValid(this._children)); |
|||
} |
|||
|
|||
void _initGap(MaterialGap gap) { |
|||
AnimationController controller = new AnimationController( |
|||
duration: ThemeUtils.kThemeAnimationDuration, |
|||
vsync: this); |
|||
|
|||
CurvedAnimation startAnimation = new CurvedAnimation( |
|||
parent: controller, |
|||
curve: Curves.fastOutSlowIn); |
|||
|
|||
CurvedAnimation endAnimation = new CurvedAnimation( |
|||
parent: controller, |
|||
curve: Curves.fastOutSlowIn); |
|||
|
|||
CurvedAnimation gapAnimation = new CurvedAnimation( |
|||
parent: controller, |
|||
curve: Curves.fastOutSlowIn); |
|||
|
|||
controller.addListener(this._handleTick); |
|||
|
|||
this._animationTuples[gap.key] = new _AnimationTuple( |
|||
controller: controller, |
|||
startAnimation: startAnimation, |
|||
endAnimation: endAnimation, |
|||
gapAnimation: gapAnimation); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
foreach (var child in this._children) { |
|||
if (child is MaterialGap) { |
|||
this._animationTuples[child.key].controller.dispose(); |
|||
} |
|||
} |
|||
|
|||
base.dispose(); |
|||
} |
|||
|
|||
|
|||
void _handleTick() { |
|||
this.setState(() => { }); |
|||
} |
|||
|
|||
bool _debugHasConsecutiveGaps(List<MergeableMaterialItem> children) { |
|||
for (int i = 0; i < this.widget.children.Count - 1; i++) { |
|||
if (this.widget.children[i] is MaterialGap && |
|||
this.widget.children[i + 1] is MaterialGap) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool _debugGapsAreValid(List<MergeableMaterialItem> children) { |
|||
if (this._debugHasConsecutiveGaps(children)) { |
|||
return false; |
|||
} |
|||
|
|||
if (children.isNotEmpty()) { |
|||
if (children.first() is MaterialGap || children.last() is MaterialGap) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void _insertChild(int index, MergeableMaterialItem child) { |
|||
this._children.Insert(index, child); |
|||
|
|||
if (child is MaterialGap) { |
|||
this._initGap((MaterialGap) child); |
|||
} |
|||
} |
|||
|
|||
void _removeChild(int index) { |
|||
MergeableMaterialItem child = this._children[index]; |
|||
this._children.RemoveAt(index); |
|||
|
|||
if (child is MaterialGap) { |
|||
this._animationTuples[child.key] = null; |
|||
} |
|||
} |
|||
|
|||
bool _isClosingGap(int index) { |
|||
if (index < this._children.Count - 1 && this._children[index] is MaterialGap) { |
|||
return this._animationTuples[this._children[index].key].controller.status == AnimationStatus.reverse; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void _removeEmptyGaps() { |
|||
int j = 0; |
|||
|
|||
while (j < this._children.Count) { |
|||
if (this._children[j] is MaterialGap && |
|||
this._animationTuples[this._children[j].key].controller.status == AnimationStatus.dismissed) { |
|||
this._removeChild(j); |
|||
} |
|||
else { |
|||
j++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
MergeableMaterial _oldWidget = (MergeableMaterial) oldWidget; |
|||
base.didUpdateWidget(_oldWidget); |
|||
|
|||
HashSet<LocalKey> oldKeys = new HashSet<LocalKey>(); |
|||
foreach (var child in _oldWidget.children) { |
|||
oldKeys.Add(child.key); |
|||
} |
|||
|
|||
HashSet<LocalKey> newKeys = new HashSet<LocalKey>(); |
|||
foreach (var child in this.widget.children) { |
|||
newKeys.Add(child.key); |
|||
} |
|||
|
|||
HashSet<LocalKey> newOnly = new HashSet<LocalKey>(); |
|||
foreach (var key in newKeys) { |
|||
if (!oldKeys.Contains(key)) { |
|||
newOnly.Add(key); |
|||
} |
|||
} |
|||
|
|||
HashSet<LocalKey> oldOnly = new HashSet<LocalKey>(); |
|||
foreach (var key in oldKeys) { |
|||
if (!newKeys.Contains(key)) { |
|||
oldOnly.Add(key); |
|||
} |
|||
} |
|||
|
|||
List<MergeableMaterialItem> newChildren = this.widget.children; |
|||
int i = 0; |
|||
int j = 0; |
|||
|
|||
D.assert(this._debugGapsAreValid(newChildren)); |
|||
this._removeEmptyGaps(); |
|||
|
|||
while (i < newChildren.Count && j < this._children.Count) { |
|||
if (newOnly.Contains(newChildren[i].key) || |
|||
oldOnly.Contains(this._children[j].key)) { |
|||
int startNew = i; |
|||
int startOld = j; |
|||
|
|||
while (newOnly.Contains(newChildren[i].key)) { |
|||
i++; |
|||
} |
|||
|
|||
while (oldOnly.Contains(this._children[j].key) || this._isClosingGap(j)) { |
|||
j++; |
|||
} |
|||
|
|||
int newLength = i - startNew; |
|||
int oldLength = j - startOld; |
|||
|
|||
if (newLength > 0) { |
|||
if (oldLength > 1 || oldLength == 1 && this._children[startOld] is MaterialSlice) { |
|||
if (newLength == 1 && newChildren[startNew] is MaterialGap) { |
|||
double gapSizeSum = 0.0; |
|||
|
|||
while (startOld < j) { |
|||
if (this._children[startOld] is MaterialGap) { |
|||
MaterialGap gap = (MaterialGap) this._children[startOld]; |
|||
gapSizeSum += gap.size; |
|||
} |
|||
|
|||
this._removeChild(startOld); |
|||
j--; |
|||
} |
|||
|
|||
this._insertChild(startOld, newChildren[startNew]); |
|||
this._animationTuples[newChildren[startNew].key].gapStart = gapSizeSum; |
|||
this._animationTuples[newChildren[startNew].key].controller.forward(); |
|||
j++; |
|||
} |
|||
else { |
|||
for (int k = 0; k < oldLength; k++) { |
|||
this._removeChild(startOld); |
|||
} |
|||
|
|||
for (int k = 0; k < newLength; k++) { |
|||
this._insertChild(startOld + k, newChildren[startNew + k]); |
|||
} |
|||
|
|||
j += (newLength - oldLength); |
|||
} |
|||
} |
|||
else if (oldLength == 1) { |
|||
if (newLength == 1 && newChildren[startNew] is MaterialGap && |
|||
this._children[startOld].key == newChildren[startNew].key) { |
|||
this._animationTuples[newChildren[startNew].key].controller.forward(); |
|||
} |
|||
else { |
|||
double gapSize = this._getGapSize(startOld); |
|||
|
|||
this._removeChild(startOld); |
|||
|
|||
for (int k = 0; k < newLength; k++) { |
|||
this._insertChild(startOld + k, newChildren[startNew + k]); |
|||
} |
|||
|
|||
j += (newLength - 1); |
|||
double gapSizeSum = 0.0; |
|||
|
|||
for (int k = startNew; k < i; k++) { |
|||
if (newChildren[k] is MaterialGap) { |
|||
MaterialGap gap = (MaterialGap) newChildren[k]; |
|||
gapSizeSum += gap.size; |
|||
} |
|||
} |
|||
|
|||
for (int k = startNew; k < i; k++) { |
|||
if (newChildren[k] is MaterialGap) { |
|||
MaterialGap gap = (MaterialGap) newChildren[k]; |
|||
|
|||
this._animationTuples[gap.key].gapStart = gapSize * gap.size / gapSizeSum; |
|||
this._animationTuples[gap.key].controller.setValue(0.0); |
|||
this._animationTuples[gap.key].controller.forward(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
for (int k = 0; k < newLength; k++) { |
|||
this._insertChild(startOld + k, newChildren[startNew + k]); |
|||
|
|||
if (newChildren[startNew + k] is MaterialGap) { |
|||
MaterialGap gap = (MaterialGap) newChildren[startNew + k]; |
|||
this._animationTuples[gap.key].controller.forward(); |
|||
} |
|||
} |
|||
|
|||
j += newLength; |
|||
} |
|||
} |
|||
else { |
|||
if (oldLength > 1 || oldLength == 1 && this._children[startOld] is MaterialSlice) { |
|||
double gapSizeSum = 0.0; |
|||
|
|||
while (startOld < j) { |
|||
if (this._children[startOld] is MaterialGap) { |
|||
MaterialGap gap = (MaterialGap) this._children[startOld]; |
|||
gapSizeSum += gap.size; |
|||
} |
|||
|
|||
this._removeChild(startOld); |
|||
j--; |
|||
} |
|||
|
|||
if (gapSizeSum != 0.0) { |
|||
MaterialGap gap = new MaterialGap(key: new UniqueKey(), size: gapSizeSum); |
|||
this._insertChild(startOld, gap); |
|||
this._animationTuples[gap.key].gapStart = 0.0; |
|||
this._animationTuples[gap.key].controller.setValue(1.0); |
|||
this._animationTuples[gap.key].controller.reverse(); |
|||
j++; |
|||
} |
|||
} |
|||
else if (oldLength == 1) { |
|||
MaterialGap gap = (MaterialGap) this._children[startOld]; |
|||
this._animationTuples[gap.key].gapStart = 0.0; |
|||
this._animationTuples[gap.key].controller.reverse(); |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
if ((this._children[j] is MaterialGap) == (newChildren[i] is MaterialGap)) { |
|||
this._children[j] = newChildren[i]; |
|||
|
|||
i++; |
|||
j++; |
|||
} |
|||
else { |
|||
D.assert(this._children[j] is MaterialGap); |
|||
j++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
while (j < this._children.Count) { |
|||
this._removeChild(j); |
|||
} |
|||
|
|||
while (i < newChildren.Count) { |
|||
this._insertChild(j, newChildren[i]); |
|||
|
|||
i++; |
|||
j++; |
|||
} |
|||
} |
|||
|
|||
|
|||
BorderRadius _borderRadius(int index, bool start, bool end) { |
|||
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft == |
|||
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topRight); |
|||
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft == |
|||
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].bottomLeft); |
|||
D.assert(MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft == |
|||
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].bottomRight); |
|||
Radius cardRadius = MaterialConstantsUtils.kMaterialEdges[MaterialType.card].topLeft; |
|||
Radius startRadius = Radius.zero; |
|||
Radius endRadius = Radius.zero; |
|||
|
|||
if (index > 0 && this._children[index - 1] is MaterialGap) { |
|||
startRadius = Radius.lerp(Radius.zero, cardRadius, |
|||
this._animationTuples[this._children[index - 1].key].startAnimation.value); |
|||
} |
|||
|
|||
if (index < this._children.Count - 2 && this._children[index + 1] is MaterialGap) { |
|||
endRadius = Radius.lerp(Radius.zero, cardRadius, |
|||
this._animationTuples[this._children[index + 1].key].endAnimation.value); |
|||
} |
|||
|
|||
if (this.widget.mainAxis == Axis.vertical) { |
|||
return BorderRadius.vertical( |
|||
top: start ? cardRadius : startRadius, |
|||
bottom: end ? cardRadius : endRadius); |
|||
} |
|||
else { |
|||
return BorderRadius.horizontal( |
|||
left: start ? cardRadius : startRadius, |
|||
right: end ? cardRadius : endRadius); |
|||
} |
|||
} |
|||
|
|||
|
|||
double _getGapSize(int index) { |
|||
MaterialGap gap = (MaterialGap) this._children[index]; |
|||
|
|||
return MathUtils.lerpDouble(this._animationTuples[gap.key].gapStart, |
|||
gap.size, |
|||
this._animationTuples[gap.key].gapAnimation.value); |
|||
} |
|||
|
|||
|
|||
bool _willNeedDivider(int index) { |
|||
if (index < 0) { |
|||
return false; |
|||
} |
|||
|
|||
if (index >= this._children.Count) { |
|||
return false; |
|||
} |
|||
|
|||
return this._children[index] is MaterialSlice || this._isClosingGap(index); |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
this._removeEmptyGaps(); |
|||
|
|||
List<Widget> widgets = new List<Widget>(); |
|||
List<Widget> slices = new List<Widget>(); |
|||
int i = 0; |
|||
|
|||
for (i = 0; i < this._children.Count; i++) { |
|||
if (this._children[i] is MaterialGap) { |
|||
D.assert(slices.isNotEmpty()); |
|||
widgets.Add( |
|||
new Container( |
|||
decoration: new BoxDecoration( |
|||
color: Theme.of(context).cardColor, |
|||
borderRadius: this._borderRadius(i - 1, widgets.isEmpty(), false), |
|||
shape: BoxShape.rectangle), |
|||
child: new ListBody( |
|||
mainAxis: this.widget.mainAxis, |
|||
children: slices) |
|||
) |
|||
); |
|||
|
|||
slices = new List<Widget>(); |
|||
widgets.Add( |
|||
new SizedBox( |
|||
width: this.widget.mainAxis == Axis.horizontal ? this._getGapSize(i) : (double?) null, |
|||
height: this.widget.mainAxis == Axis.vertical ? this._getGapSize(i) : (double?) null) |
|||
); |
|||
} |
|||
else { |
|||
MaterialSlice slice = (MaterialSlice) this._children[i]; |
|||
Widget child = slice.child; |
|||
|
|||
if (this.widget.hasDividers) { |
|||
bool hasTopDivider = this._willNeedDivider(i - 1); |
|||
bool hasBottomDivider = this._willNeedDivider(i + 1); |
|||
|
|||
Border border; |
|||
BorderSide divider = Divider.createBorderSide( |
|||
context, |
|||
width: 0.5 |
|||
); |
|||
|
|||
if (i == 0) { |
|||
border = new Border( |
|||
bottom: hasBottomDivider ? divider : BorderSide.none); |
|||
} |
|||
else if (i == this._children.Count - 1) { |
|||
border = new Border( |
|||
top: hasTopDivider ? divider : BorderSide.none); |
|||
} |
|||
else { |
|||
border = new Border( |
|||
top: hasTopDivider ? divider : BorderSide.none, |
|||
bottom: hasBottomDivider ? divider : BorderSide.none |
|||
); |
|||
} |
|||
|
|||
D.assert(border != null); |
|||
|
|||
child = new AnimatedContainer( |
|||
key: new _MergeableMaterialSliceKey(this._children[i].key), |
|||
decoration: new BoxDecoration(border: border), |
|||
duration: ThemeUtils.kThemeAnimationDuration, |
|||
curve: Curves.fastOutSlowIn, |
|||
child: child |
|||
); |
|||
} |
|||
|
|||
slices.Add( |
|||
new Material( |
|||
type: MaterialType.transparency, |
|||
child: child |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
if (slices.isNotEmpty()) { |
|||
widgets.Add( |
|||
new Container( |
|||
decoration: new BoxDecoration( |
|||
color: Theme.of(context).cardColor, |
|||
borderRadius: this._borderRadius(i - 1, widgets.isEmpty(), true), |
|||
shape: BoxShape.rectangle |
|||
), |
|||
child: new ListBody( |
|||
mainAxis: this.widget.mainAxis, |
|||
children: slices |
|||
) |
|||
) |
|||
); |
|||
slices = new List<Widget>(); |
|||
} |
|||
|
|||
return new _MergeableMaterialListBody( |
|||
mainAxis: this.widget.mainAxis, |
|||
boxShadows: ShadowConstants.kElevationToShadow[this.widget.elevation], |
|||
items: this._children, |
|||
children: widgets |
|||
); |
|||
} |
|||
} |
|||
|
|||
|
|||
class _MergeableMaterialSliceKey : GlobalKey { |
|||
public _MergeableMaterialSliceKey(LocalKey value) : base() { |
|||
this.value = value; |
|||
} |
|||
|
|||
public readonly LocalKey value; |
|||
|
|||
public bool Equals(_MergeableMaterialSliceKey other) { |
|||
if (ReferenceEquals(null, other)) { |
|||
return false; |
|||
} |
|||
|
|||
if (ReferenceEquals(this, other)) { |
|||
return true; |
|||
} |
|||
|
|||
return other.value == this.value; |
|||
} |
|||
|
|||
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((_MergeableMaterialSliceKey) obj); |
|||
} |
|||
|
|||
public static bool operator ==(_MergeableMaterialSliceKey left, _MergeableMaterialSliceKey right) { |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(_MergeableMaterialSliceKey left, _MergeableMaterialSliceKey right) { |
|||
return !Equals(left, right); |
|||
} |
|||
|
|||
public override int GetHashCode() { |
|||
unchecked { |
|||
var hashCode = this.value.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
public override string ToString() { |
|||
return "_MergeableMaterialSliceKey(" + this.value + ")"; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _MergeableMaterialListBody : ListBody { |
|||
public _MergeableMaterialListBody( |
|||
List<Widget> children = null, |
|||
Axis mainAxis = Axis.vertical, |
|||
List<MergeableMaterialItem> items = null, |
|||
List<BoxShadow> boxShadows = null) : base(children: children, mainAxis: mainAxis) { |
|||
this.items = items; |
|||
this.boxShadows = boxShadows; |
|||
} |
|||
|
|||
public readonly List<MergeableMaterialItem> items; |
|||
|
|||
public readonly List<BoxShadow> boxShadows; |
|||
|
|||
AxisDirection _getDirection(BuildContext context) { |
|||
return AxisDirectionUtils.getAxisDirectionFromAxisReverseAndDirectionality(context, this.mainAxis, false) ?? |
|||
AxisDirection.right; |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new _RenderMergeableMaterialListBody( |
|||
axisDirection: this._getDirection(context), |
|||
boxShadows: this.boxShadows |
|||
); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
_RenderMergeableMaterialListBody materialRenderListBody = (_RenderMergeableMaterialListBody) renderObject; |
|||
materialRenderListBody.axisDirection = this._getDirection(context); |
|||
materialRenderListBody.boxShadows = this.boxShadows; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _RenderMergeableMaterialListBody : RenderListBody { |
|||
public _RenderMergeableMaterialListBody( |
|||
List<RenderBox> children = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
List<BoxShadow> boxShadows = null) : base(children: children, axisDirection: axisDirection) { |
|||
this.boxShadows = boxShadows; |
|||
} |
|||
|
|||
public List<BoxShadow> boxShadows; |
|||
|
|||
void _paintShadows(Canvas canvas, Rect rect) { |
|||
foreach (BoxShadow boxShadow in this.boxShadows) { |
|||
Paint paint = boxShadow.toPaint(); |
|||
canvas.drawRRect( |
|||
MaterialConstantsUtils.kMaterialEdges[MaterialType.card].toRRect(rect), paint); |
|||
} |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
RenderBox child = this.firstChild; |
|||
int i = 0; |
|||
|
|||
while (child != null) { |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
Rect rect = (childParentData.offset + offset) & child.size; |
|||
if (i % 2 == 0) { |
|||
this._paintShadows(context.canvas, rect); |
|||
} |
|||
|
|||
child = childParentData.nextSibling; |
|||
i++; |
|||
} |
|||
|
|||
this.defaultPaint(context, offset); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5396c023280464ef08be35796d930e69 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.async; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public class Tooltip : StatefulWidget { |
|||
public Tooltip( |
|||
Key key = null, |
|||
string message = null, |
|||
double height = 32.0, |
|||
EdgeInsets padding = null, |
|||
double verticalOffset = 24.0, |
|||
bool preferBelow = true, |
|||
Widget child = null) : base(key: key) { |
|||
D.assert(message != null); |
|||
this.message = message; |
|||
this.height = height; |
|||
this.padding = padding ?? EdgeInsets.symmetric(horizontal: 16.0); |
|||
this.verticalOffset = verticalOffset; |
|||
this.preferBelow = preferBelow; |
|||
this.child = child; |
|||
} |
|||
|
|||
|
|||
public readonly string message; |
|||
|
|||
public readonly double height; |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
public readonly double verticalOffset; |
|||
|
|||
public readonly bool preferBelow; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override State createState() { |
|||
return new _TooltipState(); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new StringProperty("message", this.message, showName: false)); |
|||
properties.add(new DoubleProperty("vertical offset", this.verticalOffset)); |
|||
properties.add(new FlagProperty("position", value: this.preferBelow, ifTrue: "below", ifFalse: "above", |
|||
showName: true)); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _TooltipState : SingleTickerProviderStateMixin<Tooltip> { |
|||
AnimationController _controller; |
|||
OverlayEntry _entry; |
|||
Timer _timer; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController(duration: TooltipUtils._kFadeDuration, vsync: this); |
|||
this._controller.addStatusListener(this._handleStatusChanged); |
|||
} |
|||
|
|||
void _handleStatusChanged(AnimationStatus status) { |
|||
if (status == AnimationStatus.dismissed) { |
|||
this._removeEntry(); |
|||
} |
|||
} |
|||
|
|||
bool ensureTooltopVisible() { |
|||
if (this._entry != null) { |
|||
this._timer?.cancel(); |
|||
this._timer = null; |
|||
this._controller.forward(); |
|||
return false; |
|||
} |
|||
|
|||
RenderBox box = (RenderBox) this.context.findRenderObject(); |
|||
Offset target = box.localToGlobal(box.size.center(Offset.zero)); |
|||
|
|||
Widget overlay = new _TooltipOverlay( |
|||
message: this.widget.message, |
|||
height: this.widget.height, |
|||
padding: this.widget.padding, |
|||
animation: new CurvedAnimation( |
|||
parent: this._controller, |
|||
curve: Curves.fastOutSlowIn), |
|||
target: target, |
|||
verticalOffset: this.widget.verticalOffset, |
|||
preferBelow: this.widget.preferBelow |
|||
); |
|||
|
|||
this._entry = new OverlayEntry(builder: (BuildContext context) => overlay); |
|||
Overlay.of(this.context, debugRequiredFor: this.widget).insert(this._entry); |
|||
GestureBinding.instance.pointerRouter.addGlobalRoute(this._handlePointerEvent); |
|||
this._controller.forward(); |
|||
return true; |
|||
} |
|||
|
|||
void _removeEntry() { |
|||
D.assert(this._entry != null); |
|||
this._timer?.cancel(); |
|||
this._timer = null; |
|||
this._entry.remove(); |
|||
this._entry = null; |
|||
GestureBinding.instance.pointerRouter.removeGlobalRoute(this._handlePointerEvent); |
|||
} |
|||
|
|||
void _handlePointerEvent(PointerEvent pEvent) { |
|||
D.assert(this._entry != null); |
|||
if (pEvent is PointerUpEvent || pEvent is PointerCancelEvent) { |
|||
this._timer = this._timer ?? Window.instance.run(TooltipUtils._kShowDuration, |
|||
() => this._controller.reverse()); |
|||
} |
|||
else if (pEvent is PointerDownEvent) { |
|||
this._controller.reverse(); |
|||
} |
|||
} |
|||
|
|||
public override void deactivate() { |
|||
if (this._entry != null) { |
|||
this._controller.reverse(); |
|||
} |
|||
|
|||
base.deactivate(); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
if (this._entry != null) { |
|||
this._removeEntry(); |
|||
} |
|||
|
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _handleLongPress() { |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
D.assert(Overlay.of(context, debugRequiredFor: this.widget) != null); |
|||
return new GestureDetector( |
|||
behavior: HitTestBehavior.opaque, |
|||
onLongPress: this._handleLongPress, |
|||
child: this.widget.child |
|||
); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _TooltipPositionDelegate : SingleChildLayoutDelegate { |
|||
public _TooltipPositionDelegate( |
|||
Offset target = null, |
|||
double? verticalOffset = null, |
|||
bool? preferBelow = null) { |
|||
D.assert(target != null); |
|||
D.assert(verticalOffset != null); |
|||
D.assert(preferBelow != null); |
|||
this.target = target; |
|||
this.verticalOffset = verticalOffset ?? 0.0; |
|||
this.preferBelow = preferBelow ?? true; |
|||
} |
|||
|
|||
public readonly Offset target; |
|||
|
|||
public readonly double verticalOffset; |
|||
|
|||
public readonly bool preferBelow; |
|||
|
|||
public override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { |
|||
return constraints.loosen(); |
|||
} |
|||
|
|||
public override Offset getPositionForChild(Size size, Size childSize) { |
|||
return Geometry.positionDependentBox( |
|||
size: size, |
|||
childSize: childSize, |
|||
target: this.target, |
|||
verticalOffset: this.verticalOffset, |
|||
preferBelow: this.preferBelow); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) { |
|||
_TooltipPositionDelegate _oldDelegate = (_TooltipPositionDelegate) oldDelegate; |
|||
return this.target != _oldDelegate.target || |
|||
this.verticalOffset != _oldDelegate.verticalOffset || |
|||
this.preferBelow != _oldDelegate.preferBelow; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _TooltipOverlay : StatelessWidget { |
|||
public _TooltipOverlay( |
|||
Key key = null, |
|||
string message = null, |
|||
double? height = null, |
|||
EdgeInsets padding = null, |
|||
Animation<double> animation = null, |
|||
Offset target = null, |
|||
double? verticalOffset = null, |
|||
bool? preferBelow = null) : base(key: key) { |
|||
this.message = message; |
|||
this.height = height; |
|||
this.padding = padding; |
|||
this.animation = animation; |
|||
this.target = target; |
|||
this.verticalOffset = verticalOffset; |
|||
this.preferBelow = preferBelow; |
|||
} |
|||
|
|||
public readonly string message; |
|||
|
|||
public readonly double? height; |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
public readonly Animation<double> animation; |
|||
|
|||
public readonly Offset target; |
|||
|
|||
public readonly double? verticalOffset; |
|||
|
|||
public readonly bool? preferBelow; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
ThemeData theme = Theme.of(context); |
|||
ThemeData darkTheme = new ThemeData( |
|||
brightness: Brightness.dark, |
|||
textTheme: theme.brightness == Brightness.dark ? theme.textTheme : theme.primaryTextTheme |
|||
); |
|||
return Positioned.fill( |
|||
child: new IgnorePointer( |
|||
child: new CustomSingleChildLayout( |
|||
layoutDelegate: new _TooltipPositionDelegate( |
|||
target: this.target, |
|||
verticalOffset: this.verticalOffset, |
|||
preferBelow: this.preferBelow), |
|||
child: new FadeTransition( |
|||
opacity: this.animation, |
|||
child: new Opacity( |
|||
opacity: 0.9, |
|||
child: new ConstrainedBox( |
|||
constraints: new BoxConstraints(minHeight: this.height ?? 0.0), |
|||
child: new Container( |
|||
decoration: new BoxDecoration( |
|||
color: darkTheme.backgroundColor, |
|||
borderRadius: BorderRadius.circular(2.0)), |
|||
padding: this.padding, |
|||
child: new Center( |
|||
widthFactor: 1.0, |
|||
heightFactor: 1.0, |
|||
child: new Text(this.message, style: darkTheme.textTheme.body1) |
|||
) |
|||
) |
|||
) |
|||
) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 30129fcabe4bc4ab9968ed976197c77b |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.painting { |
|||
public static class Geometry { |
|||
public static Offset positionDependentBox( |
|||
Size size = null, |
|||
Size childSize = null, |
|||
Offset target = null, |
|||
bool? preferBelow = null, |
|||
double verticalOffset = 0.0, |
|||
double margin = 10.0) { |
|||
D.assert(size != null); |
|||
D.assert(childSize != null); |
|||
D.assert(target != null); |
|||
D.assert(preferBelow != null); |
|||
|
|||
bool fitsBelow = target.dy + verticalOffset + childSize.height <= size.height - margin; |
|||
bool fitsAbove = target.dy - verticalOffset - childSize.height >= margin; |
|||
bool tooltipBelow = (preferBelow ?? true) ? fitsBelow || !fitsAbove : !(fitsAbove || !fitsBelow); |
|||
double y = 0.0; |
|||
if (tooltipBelow) { |
|||
y = Math.Min(target.dy + verticalOffset, size.height - margin); |
|||
} |
|||
else { |
|||
y = Math.Max(target.dy - verticalOffset - childSize.height, margin); |
|||
} |
|||
|
|||
double x = 0.0; |
|||
if (size.width - margin * 2.0 < childSize.width) { |
|||
x = (size.width - childSize.width) / 2.0; |
|||
} |
|||
else { |
|||
double normalizedTargetX = target.dx.clamp(margin, size.width - margin); |
|||
double edge = margin + childSize.width / 2.0; |
|||
if (normalizedTargetX < edge) { |
|||
x = margin; |
|||
} |
|||
else if (normalizedTargetX > size.width - edge) { |
|||
x = size.width - margin - childSize.width; |
|||
} |
|||
else { |
|||
x = normalizedTargetX - childSize.width / 2.0; |
|||
} |
|||
} |
|||
|
|||
return new Offset(x, y); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 28b53a6969db84a5983aa10206fb298d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.scheduler; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.rendering { |
|||
public enum RenderAnimatedSizeState { |
|||
start, |
|||
stable, |
|||
changed, |
|||
unstable |
|||
} |
|||
|
|||
public class RenderAnimatedSize : RenderAligningShiftedBox { |
|||
public RenderAnimatedSize( |
|||
TickerProvider vsync = null, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null, |
|||
Alignment alignment = null, |
|||
RenderBox child = null |
|||
) : base(child: child, alignment: alignment ?? Alignment.center) { |
|||
D.assert(vsync != null); |
|||
D.assert(duration != null); |
|||
curve = curve ?? Curves.linear; |
|||
this._vsync = vsync; |
|||
this._controller = new AnimationController( |
|||
vsync: this.vsync, |
|||
duration: duration); |
|||
this._controller.addListener(() => { |
|||
if (this._controller.value != this._lastValue) { |
|||
this.markNeedsLayout(); |
|||
} |
|||
}); |
|||
this._animation = new CurvedAnimation( |
|||
parent: this._controller, |
|||
curve: curve); |
|||
} |
|||
|
|||
AnimationController _controller; |
|||
CurvedAnimation _animation; |
|||
SizeTween _sizeTween = new SizeTween(); |
|||
bool _hasVisualOverflow; |
|||
double _lastValue; |
|||
|
|||
public RenderAnimatedSizeState state { |
|||
get { return this._state; } |
|||
} |
|||
|
|||
RenderAnimatedSizeState _state = RenderAnimatedSizeState.start; |
|||
|
|||
public TimeSpan? duration { |
|||
get { return this._controller.duration; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (value == this._controller.duration) { |
|||
return; |
|||
} |
|||
|
|||
this._controller.duration = value; |
|||
} |
|||
} |
|||
|
|||
public Curve curve { |
|||
get { return this._animation.curve; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (value == this._animation.curve) { |
|||
return; |
|||
} |
|||
|
|||
this._animation.curve = value; |
|||
} |
|||
} |
|||
|
|||
public bool isAnimating { |
|||
get { return this._controller.isAnimating; } |
|||
} |
|||
|
|||
public TickerProvider vsync { |
|||
get { return this._vsync; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (value == this._vsync) { |
|||
return; |
|||
} |
|||
|
|||
this._vsync = value; |
|||
this._controller.resync(this.vsync); |
|||
} |
|||
} |
|||
|
|||
TickerProvider _vsync; |
|||
|
|||
public override void detach() { |
|||
this._controller.stop(); |
|||
base.detach(); |
|||
} |
|||
|
|||
Size _animatedSize { |
|||
get { return this._sizeTween.evaluate(this._animation); } |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
this._lastValue = this._controller.value; |
|||
this._hasVisualOverflow = false; |
|||
|
|||
if (this.child == null || this.constraints.isTight) { |
|||
this._controller.stop(); |
|||
this.size = this._sizeTween.begin = this._sizeTween.end = this.constraints.smallest; |
|||
this._state = RenderAnimatedSizeState.start; |
|||
this.child?.layout(this.constraints); |
|||
return; |
|||
} |
|||
|
|||
this.child.layout(this.constraints, parentUsesSize: true); |
|||
|
|||
switch (this._state) { |
|||
case RenderAnimatedSizeState.start: |
|||
this._layoutStart(); |
|||
break; |
|||
case RenderAnimatedSizeState.stable: |
|||
this._layoutStable(); |
|||
break; |
|||
case RenderAnimatedSizeState.changed: |
|||
this._layoutChanged(); |
|||
break; |
|||
case RenderAnimatedSizeState.unstable: |
|||
this._layoutUnstable(); |
|||
break; |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(this._animatedSize); |
|||
this.alignChild(); |
|||
|
|||
if (this.size.width < this._sizeTween.end.width || |
|||
this.size.height < this._sizeTween.end.height) { |
|||
this._hasVisualOverflow = true; |
|||
} |
|||
} |
|||
|
|||
void _restartAnimation() { |
|||
this._lastValue = 0.0; |
|||
this._controller.forward(from: 0.0); |
|||
} |
|||
|
|||
void _layoutStart() { |
|||
this._sizeTween.begin = this._sizeTween.end = this.debugAdoptSize(this.child.size); |
|||
this._state = RenderAnimatedSizeState.stable; |
|||
} |
|||
|
|||
void _layoutStable() { |
|||
if (this._sizeTween.end != this.child.size) { |
|||
this._sizeTween.begin = this.size; |
|||
this._sizeTween.end = this.debugAdoptSize(this.child.size); |
|||
this._restartAnimation(); |
|||
this._state = RenderAnimatedSizeState.changed; |
|||
} |
|||
else if (this._controller.value == this._controller.upperBound) { |
|||
this._sizeTween.begin = this._sizeTween.end = this.debugAdoptSize(this.child.size); |
|||
} |
|||
else if (!this._controller.isAnimating) { |
|||
this._controller.forward(); |
|||
} |
|||
} |
|||
|
|||
void _layoutChanged() { |
|||
if (this._sizeTween.end != this.child.size) { |
|||
this._sizeTween.begin = this._sizeTween.end = this.debugAdoptSize(this.child.size); |
|||
this._restartAnimation(); |
|||
this._state = RenderAnimatedSizeState.unstable; |
|||
} |
|||
else { |
|||
this._state = RenderAnimatedSizeState.stable; |
|||
if (!this._controller.isAnimating) { |
|||
this._controller.forward(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void _layoutUnstable() { |
|||
if (this._sizeTween.end != this.child.size) { |
|||
this._sizeTween.begin = this._sizeTween.end = this.debugAdoptSize(this.child.size); |
|||
this._restartAnimation(); |
|||
} |
|||
else { |
|||
this._controller.stop(); |
|||
this._state = RenderAnimatedSizeState.stable; |
|||
} |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.child != null && this._hasVisualOverflow) { |
|||
Rect rect = Offset.zero & this.size; |
|||
context.pushClipRect(this.needsCompositing, offset, rect, base.paint); |
|||
} |
|||
else { |
|||
base.paint(context, offset); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6a663c9206ccd462eb5b08e96d69e3ef |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.rendering { |
|||
public class ListBodyParentData : ContainerParentDataMixinBoxParentData<RenderBox> { |
|||
} |
|||
|
|||
|
|||
delegate double __ChildSizingFunction(RenderBox child); |
|||
|
|||
|
|||
public class RenderListBody : RenderBoxContainerDefaultsMixinContainerRenderObjectMixinRenderBox<RenderBox, |
|||
ListBodyParentData> { |
|||
public RenderListBody( |
|||
List<RenderBox> children = null, |
|||
AxisDirection axisDirection = AxisDirection.down) { |
|||
this._axisDirection = axisDirection; |
|||
this.addAll(children); |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is ListBodyParentData)) { |
|||
child.parentData = new ListBodyParentData(); |
|||
} |
|||
} |
|||
|
|||
public AxisDirection axisDirection { |
|||
get { return this._axisDirection; } |
|||
set { |
|||
if (this._axisDirection == value) { |
|||
return; |
|||
} |
|||
|
|||
this._axisDirection = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
AxisDirection _axisDirection; |
|||
|
|||
public Axis mainAxis { |
|||
get { return AxisUtils.axisDirectionToAxis(this.axisDirection); } |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
D.assert(() => { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
if (!this.constraints.hasBoundedWidth) { |
|||
return true; |
|||
} |
|||
|
|||
break; |
|||
case Axis.vertical: |
|||
if (!this.constraints.hasBoundedHeight) { |
|||
return true; |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
throw new UIWidgetsError( |
|||
"RenderListBody must have unlimited space along its main axis.\n" + |
|||
"RenderListBody does not clip or resize its children, so it must be " + |
|||
"placed in a parent that does not constrain the main " + |
|||
"axis. You probably want to put the RenderListBody inside a " + |
|||
"RenderViewport with a matching main axis."); |
|||
}); |
|||
|
|||
D.assert(() => { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
if (this.constraints.hasBoundedHeight) { |
|||
return true; |
|||
} |
|||
|
|||
break; |
|||
case Axis.vertical: |
|||
if (this.constraints.hasBoundedWidth) { |
|||
return true; |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
throw new UIWidgetsError( |
|||
"RenderListBody must have a bounded constraint for its cross axis.\n" + |
|||
"RenderListBody forces its children to expand to fit the RenderListBody\"s container, " + |
|||
"so it must be placed in a parent that constrains the cross " + |
|||
"axis to a finite dimension. If you are attempting to nest a RenderListBody with " + |
|||
"one direction inside one of another direction, you will want to " + |
|||
"wrap the inner one inside a box that fixes the dimension in that direction, " + |
|||
"for example, a RenderIntrinsicWidth or RenderIntrinsicHeight object. " + |
|||
"This is relatively expensive, however." |
|||
); |
|||
}); |
|||
|
|||
double mainAxisExtent = 0.0; |
|||
RenderBox child = this.firstChild; |
|||
BoxConstraints innerConstraints = null; |
|||
double position = 0.0; |
|||
|
|||
switch (this.axisDirection) { |
|||
case AxisDirection.right: |
|||
innerConstraints = BoxConstraints.tightFor(height: this.constraints.maxHeight); |
|||
while (child != null) { |
|||
child.layout(innerConstraints, parentUsesSize: true); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
childParentData.offset = new Offset(mainAxisExtent, 0.0); |
|||
mainAxisExtent += child.size.width; |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(new Size(mainAxisExtent, this.constraints.maxHeight)); |
|||
break; |
|||
case AxisDirection.left: |
|||
innerConstraints = BoxConstraints.tightFor(height: this.constraints.maxHeight); |
|||
while (child != null) { |
|||
child.layout(innerConstraints, parentUsesSize: true); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
mainAxisExtent += child.size.width; |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
position = 0.0; |
|||
child = this.firstChild; |
|||
while (child != null) { |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
position += child.size.width; |
|||
childParentData.offset = new Offset(mainAxisExtent - position, 0.0); |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(new Size(mainAxisExtent, this.constraints.maxHeight)); |
|||
break; |
|||
case AxisDirection.down: |
|||
innerConstraints = BoxConstraints.tightFor(width: this.constraints.maxWidth); |
|||
while (child != null) { |
|||
child.layout(innerConstraints, parentUsesSize: true); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
childParentData.offset = new Offset(0.0, mainAxisExtent); |
|||
mainAxisExtent += child.size.height; |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(new Size(this.constraints.maxWidth, mainAxisExtent)); |
|||
break; |
|||
case AxisDirection.up: |
|||
innerConstraints = BoxConstraints.tightFor(width: this.constraints.maxWidth); |
|||
while (child != null) { |
|||
child.layout(innerConstraints, parentUsesSize: true); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
mainAxisExtent += child.size.height; |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
position = 0.0; |
|||
child = this.firstChild; |
|||
while (child != null) { |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
position += child.size.height; |
|||
childParentData.offset = new Offset(0.0, mainAxisExtent - position); |
|||
D.assert(child.parentData == childParentData); |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
this.size = this.constraints.constrain(new Size(this.constraints.maxWidth, mainAxisExtent)); |
|||
break; |
|||
} |
|||
|
|||
D.assert(this.size.isFinite); |
|||
} |
|||
|
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<AxisDirection>("axisDirection", this.axisDirection)); |
|||
} |
|||
|
|||
double _getIntrinsicCrossAxis(__ChildSizingFunction childSize) { |
|||
double extent = 0.0; |
|||
RenderBox child = this.firstChild; |
|||
while (child != null) { |
|||
extent = Math.Max(extent, childSize(child)); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
return extent; |
|||
} |
|||
|
|||
double _getIntrinsicMainAxis(__ChildSizingFunction childSize) { |
|||
double extent = 0.0; |
|||
RenderBox child = this.firstChild; |
|||
while (child != null) { |
|||
extent += childSize(child); |
|||
ListBodyParentData childParentData = (ListBodyParentData) child.parentData; |
|||
child = childParentData.nextSibling; |
|||
} |
|||
|
|||
return extent; |
|||
} |
|||
|
|||
|
|||
protected override double computeMinIntrinsicWidth(double height) { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
return this._getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicWidth(height)); |
|||
case Axis.vertical: |
|||
return this._getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicWidth(height)); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
|
|||
protected override double computeMaxIntrinsicWidth(double height) { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
return this._getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicWidth(height)); |
|||
case Axis.vertical: |
|||
return this._getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicWidth(height)); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
|
|||
protected override double computeMinIntrinsicHeight(double width) { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
return this._getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicHeight(width)); |
|||
case Axis.vertical: |
|||
return this._getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicHeight(width)); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
|
|||
protected override double computeMaxIntrinsicHeight(double width) { |
|||
switch (this.mainAxis) { |
|||
case Axis.horizontal: |
|||
return this._getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicHeight(width)); |
|||
case Axis.vertical: |
|||
return this._getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicHeight(width)); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
|
|||
protected override double? computeDistanceToActualBaseline(TextBaseline baseline) { |
|||
return this.defaultComputeDistanceToFirstActualBaseline(baseline); |
|||
} |
|||
|
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
this.defaultPaint(context, offset); |
|||
} |
|||
|
|||
|
|||
protected override bool hitTestChildren(HitTestResult result, Offset position = null) { |
|||
return this.defaultHitTestChildren(result, position: position); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3d05c7f8f5b324c95af73a07d3608715 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.painting; |
|||
|
|||
namespace Unity.UIWidgets.rendering { |
|||
public class AlignmentTween : Tween<Alignment> { |
|||
public AlignmentTween( |
|||
Alignment begin = null, |
|||
Alignment end = null) |
|||
: base(begin: begin, end: end) { |
|||
} |
|||
|
|||
public override Alignment lerp(double t) { |
|||
return Alignment.lerp(this.begin, this.end, t); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 44e6cc749adfb43a788ba4979e53ddcc |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.utils { |
|||
public class AxisDirectionUtils { |
|||
public static AxisDirection? getAxisDirectionFromAxisReverseAndDirectionality( |
|||
BuildContext context, |
|||
Axis axis, |
|||
bool reverse) { |
|||
switch (axis) { |
|||
case Axis.horizontal: |
|||
return reverse ? AxisDirection.right : AxisDirection.left; |
|||
case Axis.vertical: |
|||
return reverse ? AxisDirection.up : AxisDirection.down; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 9dd3903a956dd4113a1f550c6cb76f28 |
|||
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; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public enum CrossFadeState { |
|||
showFirst, |
|||
showSecond |
|||
} |
|||
|
|||
public delegate Widget AnimatedCrossFadeBuilder(Widget topChild, Key topChildKey, Widget bottomChild, |
|||
Key bottomChildKey); |
|||
|
|||
|
|||
public class AnimatedCrossFade : StatefulWidget { |
|||
public AnimatedCrossFade( |
|||
Key key = null, |
|||
Widget firstChild = null, |
|||
Widget secondChild = null, |
|||
Curve firstCurve = null, |
|||
Curve secondCurve = null, |
|||
Curve sizeCurve = null, |
|||
Alignment alignment = null, |
|||
CrossFadeState? crossFadeState = null, |
|||
TimeSpan? duration = null, |
|||
AnimatedCrossFadeBuilder layoutBuilder = null |
|||
) : base(key: key) { |
|||
D.assert(firstChild != null); |
|||
D.assert(secondChild != null); |
|||
D.assert(crossFadeState != null); |
|||
D.assert(duration != null); |
|||
this.firstChild = firstChild; |
|||
this.secondChild = secondChild; |
|||
this.firstCurve = firstCurve ?? Curves.linear; |
|||
this.secondCurve = secondCurve ?? Curves.linear; |
|||
this.sizeCurve = sizeCurve ?? Curves.linear; |
|||
this.alignment = alignment ?? Alignment.topCenter; |
|||
this.crossFadeState = crossFadeState ?? CrossFadeState.showFirst; |
|||
this.duration = duration ?? TimeSpan.Zero; |
|||
this.layoutBuilder = layoutBuilder ?? defaultLayoutBuilder; |
|||
} |
|||
|
|||
public readonly Widget firstChild; |
|||
|
|||
public readonly Widget secondChild; |
|||
|
|||
public readonly CrossFadeState crossFadeState; |
|||
|
|||
public readonly TimeSpan duration; |
|||
|
|||
public readonly Curve firstCurve; |
|||
|
|||
public readonly Curve secondCurve; |
|||
|
|||
public readonly Curve sizeCurve; |
|||
|
|||
public readonly Alignment alignment; |
|||
|
|||
public readonly AnimatedCrossFadeBuilder layoutBuilder; |
|||
|
|||
static Widget defaultLayoutBuilder(Widget topChild, Key topChildKey, Widget bottomChild, Key bottomChildKey) { |
|||
return new Stack( |
|||
overflow: Overflow.visible, |
|||
children: new List<Widget> { |
|||
new Positioned( |
|||
key: bottomChildKey, |
|||
left: 0.0, |
|||
top: 0.0, |
|||
right: 0.0, |
|||
child: bottomChild), |
|||
new Positioned( |
|||
key: topChildKey, |
|||
child: topChild) |
|||
}); |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new _AnimatedCrossFadeState(); |
|||
} |
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new EnumProperty<CrossFadeState>("crossFadeState", this.crossFadeState)); |
|||
properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment, |
|||
defaultValue: Alignment.topCenter)); |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _AnimatedCrossFadeState : TickerProviderStateMixin<AnimatedCrossFade> { |
|||
AnimationController _controller; |
|||
Animation<double> _firstAnimation; |
|||
Animation<double> _secondAnimation; |
|||
|
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController(duration: this.widget.duration, vsync: this); |
|||
if (this.widget.crossFadeState == CrossFadeState.showSecond) { |
|||
this._controller.setValue(1.0); |
|||
} |
|||
|
|||
this._firstAnimation = this._initAnimation(this.widget.firstCurve, true); |
|||
this._secondAnimation = this._initAnimation(this.widget.secondCurve, false); |
|||
this._controller.addStatusListener((AnimationStatus status) => { this.setState(() => { }); }); |
|||
} |
|||
|
|||
Animation<double> _initAnimation(Curve curve, bool inverted) { |
|||
Animation<double> result = this._controller.drive(new CurveTween(curve: curve)); |
|||
if (inverted) { |
|||
result = result.drive(new DoubleTween(begin: 1.0, end: 0.0)); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
AnimatedCrossFade _oldWidget = (AnimatedCrossFade) oldWidget; |
|||
if (this.widget.duration != _oldWidget.duration) { |
|||
this._controller.duration = this.widget.duration; |
|||
} |
|||
|
|||
if (this.widget.firstCurve != _oldWidget.firstCurve) { |
|||
this._firstAnimation = this._initAnimation(this.widget.firstCurve, true); |
|||
} |
|||
|
|||
if (this.widget.secondCurve != _oldWidget.secondCurve) { |
|||
this._secondAnimation = this._initAnimation(this.widget.secondCurve, false); |
|||
} |
|||
|
|||
if (this.widget.crossFadeState != _oldWidget.crossFadeState) { |
|||
switch (this.widget.crossFadeState) { |
|||
case CrossFadeState.showFirst: |
|||
this._controller.reverse(); |
|||
break; |
|||
case CrossFadeState.showSecond: |
|||
this._controller.forward(); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool _isTransitioning { |
|||
get { |
|||
return this._controller.status == AnimationStatus.forward || |
|||
this._controller.status == AnimationStatus.reverse; |
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Key kFirstChildKey = new ValueKey<CrossFadeState>(CrossFadeState.showFirst); |
|||
Key kSecondChildKey = new ValueKey<CrossFadeState>(CrossFadeState.showSecond); |
|||
bool transitioningForwards = this._controller.status == AnimationStatus.completed || |
|||
this._controller.status == AnimationStatus.forward; |
|||
|
|||
Key topKey; |
|||
Widget topChild; |
|||
Animation<double> topAnimation; |
|||
Key bottomKey; |
|||
Widget bottomChild; |
|||
Animation<double> bottomAnimation; |
|||
if (transitioningForwards) { |
|||
topKey = kSecondChildKey; |
|||
topChild = this.widget.secondChild; |
|||
topAnimation = this._secondAnimation; |
|||
bottomKey = kFirstChildKey; |
|||
bottomChild = this.widget.firstChild; |
|||
bottomAnimation = this._firstAnimation; |
|||
} |
|||
else { |
|||
topKey = kFirstChildKey; |
|||
topChild = this.widget.firstChild; |
|||
topAnimation = this._firstAnimation; |
|||
bottomKey = kSecondChildKey; |
|||
bottomChild = this.widget.secondChild; |
|||
bottomAnimation = this._secondAnimation; |
|||
} |
|||
|
|||
bottomChild = new TickerMode( |
|||
key: bottomKey, |
|||
enabled: this._isTransitioning, |
|||
child: new FadeTransition( |
|||
opacity: bottomAnimation, |
|||
child: bottomChild |
|||
) |
|||
); |
|||
|
|||
topChild = new TickerMode( |
|||
key: topKey, |
|||
enabled: true, |
|||
child: new FadeTransition( |
|||
opacity: topAnimation, |
|||
child: topChild |
|||
) |
|||
); |
|||
|
|||
return new ClipRect( |
|||
child: new AnimatedSize( |
|||
alignment: this.widget.alignment, |
|||
duration: this.widget.duration, |
|||
curve: this.widget.sizeCurve, |
|||
vsync: this, |
|||
child: this.widget.layoutBuilder(topChild, topKey, bottomChild, bottomKey |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder description) { |
|||
base.debugFillProperties(description); |
|||
description.add(new EnumProperty<CrossFadeState>("crossFadeState", this.widget.crossFadeState)); |
|||
description.add( |
|||
new DiagnosticsProperty<AnimationController>("controller", this._controller, showName: false)); |
|||
description.add(new DiagnosticsProperty<Alignment>("alignment", this.widget.alignment, |
|||
defaultValue: Alignment.topCenter)); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e07fee7cc6c4142c28e36ca221b33d7f |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.scheduler; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class AnimatedSize : SingleChildRenderObjectWidget { |
|||
public AnimatedSize( |
|||
Key key = null, |
|||
Widget child = null, |
|||
Alignment alignment = null, |
|||
Curve curve = null, |
|||
TimeSpan? duration = null, |
|||
TickerProvider vsync = null) : base(key: key, child: child) { |
|||
D.assert(duration != null); |
|||
D.assert(vsync != null); |
|||
this.alignment = alignment ?? Alignment.center; |
|||
this.curve = curve ?? Curves.linear; |
|||
this.duration = duration ?? TimeSpan.Zero; |
|||
this.vsync = vsync; |
|||
} |
|||
|
|||
public readonly Alignment alignment; |
|||
|
|||
public readonly Curve curve; |
|||
|
|||
public readonly TimeSpan duration; |
|||
|
|||
public readonly TickerProvider vsync; |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new RenderAnimatedSize( |
|||
alignment: this.alignment, |
|||
duration: this.duration, |
|||
curve: this.curve, |
|||
vsync: this.vsync); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
RenderAnimatedSize _renderObject = (RenderAnimatedSize) renderObject; |
|||
_renderObject.alignment = this.alignment; |
|||
_renderObject.duration = this.duration; |
|||
_renderObject.curve = this.curve; |
|||
_renderObject.vsync = this.vsync; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 97559cdfb3bbf44ef99317610a219a1e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class SafeArea : StatelessWidget { |
|||
public SafeArea( |
|||
Key key = null, |
|||
bool left = true, |
|||
bool top = true, |
|||
bool right = true, |
|||
bool bottom = true, |
|||
EdgeInsets mininum = null, |
|||
Widget child = null) : base(key: key) { |
|||
D.assert(child != null); |
|||
this.left = left; |
|||
this.top = top; |
|||
this.right = right; |
|||
this.bottom = bottom; |
|||
this.minimum = mininum ?? EdgeInsets.zero; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly bool left; |
|||
|
|||
public readonly bool top; |
|||
|
|||
public readonly bool right; |
|||
|
|||
public readonly bool bottom; |
|||
|
|||
public readonly EdgeInsets minimum; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
EdgeInsets padding = MediaQuery.of(context).padding; |
|||
return new Padding( |
|||
padding: EdgeInsets.only( |
|||
left: Math.Max(this.left ? padding.left : 0.0, this.minimum.left), |
|||
top: Math.Max(this.top ? padding.top : 0.0, this.minimum.top), |
|||
right: Math.Max(this.right ? padding.right : 0.0, this.minimum.right), |
|||
bottom: Math.Max(this.bottom ? padding.bottom : 0.0, this.minimum.bottom) |
|||
), |
|||
child: MediaQuery.removePadding( |
|||
context: context, |
|||
removeLeft: this.left, |
|||
removeTop: this.top, |
|||
removeRight: this.right, |
|||
removeBottom: this.bottom, |
|||
child: this.child)); |
|||
} |
|||
|
|||
|
|||
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|||
base.debugFillProperties(properties); |
|||
properties.add(new FlagProperty("left", value: this.left, ifTrue: "avoid left padding")); |
|||
properties.add(new FlagProperty("top", value: this.top, ifTrue: "avoid top padding")); |
|||
properties.add(new FlagProperty("right", value: this.right, ifTrue: "avoid right padding")); |
|||
properties.add(new FlagProperty("bottom", value: this.bottom, ifTrue: "avoid bottom padding")); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b2ccc9ab0281442d6a12b7f106cff033 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.utils; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public class SingleChildScrollView : StatelessWidget { |
|||
public SingleChildScrollView( |
|||
Key key = null, |
|||
Axis scrollDirection = Axis.vertical, |
|||
bool reverse = false, |
|||
EdgeInsets padding = null, |
|||
bool? primary = null, |
|||
ScrollPhysics physics = null, |
|||
ScrollController controller = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
D.assert(!(controller != null && primary == true), |
|||
"Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. " + |
|||
"You cannot both set primary to true and pass an explicit controller."); |
|||
this.scrollDirection = scrollDirection; |
|||
this.reverse = reverse; |
|||
this.padding = padding; |
|||
this.primary = primary ?? controller == null && scrollDirection == Axis.vertical; |
|||
this.physics = physics; |
|||
this.controller = controller; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly Axis scrollDirection; |
|||
|
|||
public readonly bool reverse; |
|||
|
|||
public readonly EdgeInsets padding; |
|||
|
|||
public readonly ScrollController controller; |
|||
|
|||
public readonly bool primary; |
|||
|
|||
public readonly ScrollPhysics physics; |
|||
|
|||
public readonly Widget child; |
|||
|
|||
|
|||
AxisDirection? _getDirection(BuildContext context) { |
|||
return AxisDirectionUtils.getAxisDirectionFromAxisReverseAndDirectionality(context, this.scrollDirection, |
|||
this.reverse); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
AxisDirection axisDirection = this._getDirection(context) ?? AxisDirection.down; |
|||
Widget contents = this.child; |
|||
if (this.padding != null) { |
|||
contents = new Padding( |
|||
padding: this.padding, |
|||
child: contents); |
|||
} |
|||
|
|||
ScrollController scrollController = this.primary |
|||
? PrimaryScrollController.of(context) |
|||
: this.controller; |
|||
|
|||
Scrollable scrollable = new Scrollable( |
|||
axisDirection: axisDirection, |
|||
controller: scrollController, |
|||
physics: this.physics, |
|||
viewportBuilder: (BuildContext subContext, ViewportOffset offset) => { |
|||
return new _SingleChildViewport( |
|||
axisDirection: axisDirection, |
|||
offset: offset, |
|||
child: contents); |
|||
} |
|||
); |
|||
|
|||
if (this.primary && scrollController != null) { |
|||
return PrimaryScrollController.none(child: scrollable); |
|||
} |
|||
|
|||
return scrollable; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _SingleChildViewport : SingleChildRenderObjectWidget { |
|||
public _SingleChildViewport( |
|||
Key key = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
ViewportOffset offset = null, |
|||
Widget child = null |
|||
) : base(key: key, child: child) { |
|||
this.axisDirection = axisDirection; |
|||
this.offset = offset; |
|||
} |
|||
|
|||
public readonly AxisDirection axisDirection; |
|||
public readonly ViewportOffset offset; |
|||
|
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
return new _RenderSingleChildViewport( |
|||
axisDirection: this.axisDirection, |
|||
offset: this.offset |
|||
); |
|||
} |
|||
|
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
_RenderSingleChildViewport _renderObject = (_RenderSingleChildViewport) renderObject; |
|||
_renderObject.axisDirection = this.axisDirection; |
|||
_renderObject.offset = this.offset; |
|||
} |
|||
} |
|||
|
|||
|
|||
class _RenderSingleChildViewport : RenderObjectWithChildMixinRenderBox<RenderBox>, RenderAbstractViewport { |
|||
public _RenderSingleChildViewport( |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
ViewportOffset offset = null, |
|||
double cacheExtent = RenderViewportUtils.defaultCacheExtent, |
|||
RenderBox child = null) { |
|||
D.assert(offset != null); |
|||
this._axisDirection = axisDirection; |
|||
this._offset = offset; |
|||
this._cacheExtent = cacheExtent; |
|||
this.child = child; |
|||
} |
|||
|
|||
public new RenderObject parent { |
|||
get { return (RenderObject) base.parent; } |
|||
} |
|||
|
|||
public AxisDirection axisDirection { |
|||
get { return this._axisDirection; } |
|||
set { |
|||
if (value == this._axisDirection) { |
|||
return; |
|||
} |
|||
|
|||
this._axisDirection = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
AxisDirection _axisDirection; |
|||
|
|||
public Axis axis { |
|||
get { return AxisUtils.axisDirectionToAxis(this.axisDirection); } |
|||
} |
|||
|
|||
public ViewportOffset offset { |
|||
get { return this._offset; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (value == this._offset) { |
|||
return; |
|||
} |
|||
|
|||
if (this.attached) { |
|||
this.offset.removeListener(this._hasScrolled); |
|||
} |
|||
|
|||
this.offset = value; |
|||
if (this.attached) { |
|||
this._offset.addListener(this._hasScrolled); |
|||
} |
|||
|
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
ViewportOffset _offset; |
|||
|
|||
public double cacheExtent { |
|||
get { return this._cacheExtent; } |
|||
set { |
|||
if (value == this._cacheExtent) { |
|||
return; |
|||
} |
|||
|
|||
this._cacheExtent = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
double _cacheExtent; |
|||
|
|||
void _hasScrolled() { |
|||
this.markNeedsPaint(); |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is ParentData)) { |
|||
child.parentData = new ParentData(); |
|||
} |
|||
} |
|||
|
|||
public override void attach(object owner) { |
|||
base.attach(owner); |
|||
this._offset.addListener(this._hasScrolled); |
|||
} |
|||
|
|||
public override void detach() { |
|||
this._offset.removeListener(this._hasScrolled); |
|||
base.detach(); |
|||
} |
|||
|
|||
public override bool isRepaintBoundary { |
|||
get { return true; } |
|||
} |
|||
|
|||
|
|||
double _viewportExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
switch (this.axis) { |
|||
case Axis.horizontal: |
|||
return this.size.width; |
|||
case Axis.vertical: |
|||
return this.size.height; |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
double _minScrollExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
double _maxScrollExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
if (this.child == null) { |
|||
return 0.0; |
|||
} |
|||
|
|||
switch (this.axis) { |
|||
case Axis.horizontal: |
|||
return Math.Max(0.0, this.child.size.width - this.size.width); |
|||
case Axis.vertical: |
|||
return Math.Max(0.0, this.child.size.height - this.size.height); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
} |
|||
|
|||
BoxConstraints _getInnerConstraints(BoxConstraints constraints) { |
|||
switch (this.axis) { |
|||
case Axis.horizontal: |
|||
return constraints.heightConstraints(); |
|||
case Axis.vertical: |
|||
return constraints.widthConstraints(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
protected override double computeMinIntrinsicWidth(double height) { |
|||
if (this.child != null) { |
|||
return this.child.getMinIntrinsicWidth(height); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicWidth(double height) { |
|||
if (this.child != null) { |
|||
return this.child.getMaxIntrinsicWidth(height); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMinIntrinsicHeight(double width) { |
|||
if (this.child != null) { |
|||
return this.child.getMinIntrinsicHeight(width); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
protected override double computeMaxIntrinsicHeight(double width) { |
|||
if (this.child != null) { |
|||
return this.child.getMaxIntrinsicHeight(width); |
|||
} |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
if (this.child == null) { |
|||
this.size = this.constraints.smallest; |
|||
} |
|||
else { |
|||
this.child.layout(this._getInnerConstraints(this.constraints), parentUsesSize: true); |
|||
this.size = this.constraints.constrain(this.child.size); |
|||
} |
|||
|
|||
this.offset.applyViewportDimension(this._viewportExtent); |
|||
this.offset.applyContentDimensions(this._minScrollExtent, this._maxScrollExtent); |
|||
} |
|||
|
|||
Offset _paintOffset { |
|||
get { return this._paintOffsetForPosition(this.offset.pixels); } |
|||
} |
|||
|
|||
Offset _paintOffsetForPosition(double position) { |
|||
D.assert(this.axisDirection != null); |
|||
switch (this.axisDirection) { |
|||
case AxisDirection.up: |
|||
return new Offset(0.0, position - this.child.size.height + this.size.height); |
|||
case AxisDirection.down: |
|||
return new Offset(0.0, -position); |
|||
case AxisDirection.left: |
|||
return new Offset(position - this.child.size.width + this.size.width, 0.0); |
|||
case AxisDirection.right: |
|||
return new Offset(-position, 0.0); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
bool _shouldClipAtPaintOffset(Offset paintOffset) { |
|||
D.assert(this.child != null); |
|||
return paintOffset < Offset.zero || |
|||
!(Offset.zero & this.size).contains((paintOffset & this.child.size).bottomRight); |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.child != null) { |
|||
Offset paintOffset = this._paintOffset; |
|||
|
|||
void paintContents(PaintingContext subContext, Offset SubOffset) { |
|||
subContext.paintChild(this.child, SubOffset + paintOffset); |
|||
} |
|||
|
|||
if (this._shouldClipAtPaintOffset(paintOffset)) { |
|||
context.pushClipRect(this.needsCompositing, offset, Offset.zero & this.size, paintContents); |
|||
} |
|||
else { |
|||
paintContents(context, offset); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void applyPaintTransform(RenderObject child, Matrix3 transform) { |
|||
Offset paintOffset = this._paintOffset; |
|||
transform.preTranslate((float) paintOffset.dx, (float) paintOffset.dy); |
|||
} |
|||
|
|||
public override Rect describeApproximatePaintClip(RenderObject child) { |
|||
if (child != null && this._shouldClipAtPaintOffset(this._paintOffset)) { |
|||
return Offset.zero & this.size; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected override bool hitTestChildren(HitTestResult result, Offset position = null) { |
|||
if (this.child != null) { |
|||
Offset transformed = position + -this._paintOffset; |
|||
return this.child.hitTest(result, position: transformed); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
public RevealedOffset getOffsetToReveal(RenderObject target, double alignment, Rect rect = null) { |
|||
rect = rect ?? target.paintBounds; |
|||
if (!(target is RenderBox)) { |
|||
return new RevealedOffset(offset: this.offset.pixels, rect: rect); |
|||
} |
|||
|
|||
RenderBox targetBox = (RenderBox) target; |
|||
Matrix3 transform = targetBox.getTransformTo(this); |
|||
Rect bounds = transform.mapRect(rect); |
|||
Size contentSize = this.child.size; |
|||
|
|||
double leadingScrollOffset = 0.0; |
|||
double targetMainAxisExtent = 0.0; |
|||
double mainAxisExtent = 0.0; |
|||
|
|||
D.assert(this.axisDirection != null); |
|||
switch (this.axisDirection) { |
|||
case AxisDirection.up: |
|||
mainAxisExtent = this.size.height; |
|||
leadingScrollOffset = contentSize.height - bounds.bottom; |
|||
targetMainAxisExtent = bounds.height; |
|||
break; |
|||
case AxisDirection.right: |
|||
mainAxisExtent = this.size.width; |
|||
leadingScrollOffset = bounds.left; |
|||
targetMainAxisExtent = bounds.width; |
|||
break; |
|||
case AxisDirection.down: |
|||
mainAxisExtent = this.size.height; |
|||
leadingScrollOffset = bounds.top; |
|||
targetMainAxisExtent = bounds.height; |
|||
break; |
|||
case AxisDirection.left: |
|||
mainAxisExtent = this.size.width; |
|||
leadingScrollOffset = contentSize.width - bounds.right; |
|||
targetMainAxisExtent = bounds.width; |
|||
break; |
|||
} |
|||
|
|||
double targetOffset = leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment; |
|||
Rect targetRect = bounds.shift(this._paintOffsetForPosition(targetOffset)); |
|||
return new RevealedOffset(offset: targetOffset, rect: targetRect); |
|||
} |
|||
|
|||
public override void showOnScreen( |
|||
RenderObject descendant, |
|||
Rect rect, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null |
|||
) { |
|||
if (!this.offset.allowImplicitScrolling) { |
|||
base.showOnScreen( |
|||
descendant: descendant, |
|||
rect: rect, |
|||
duration: duration, |
|||
curve: curve |
|||
); |
|||
} |
|||
|
|||
Rect newRect = RenderViewport.showInViewport( |
|||
descendant: descendant, |
|||
viewport: this, |
|||
offset: this.offset, |
|||
rect: rect, |
|||
duration: duration, |
|||
curve: curve); |
|||
|
|||
base.showOnScreen( |
|||
rect: newRect, |
|||
duration: duration, |
|||
curve: curve); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a72287ca8d773446497b6b89abc13f83 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using Unity.UIWidgets.engine; |
|||
using Unity.UIWidgets.widgets; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using Material = Unity.UIWidgets.material.Material; |
|||
|
|||
namespace UIWidgetsSample { |
|||
public class ExpansionPanelCanvas : WidgetCanvas { |
|||
protected override Widget getWidget() { |
|||
return new ExpansionPanelWidget(); |
|||
} |
|||
|
|||
class ExpansionPanelWidget : StatefulWidget { |
|||
public ExpansionPanelWidget(Key key = null) : base(key) { |
|||
} |
|||
|
|||
public override State createState() { |
|||
return new ExpansionPanelWidgetState(); |
|||
} |
|||
} |
|||
|
|||
class ExpansionPanelWidgetState : State<ExpansionPanelWidget> { |
|||
List<bool> isExpand = new List<bool>{false, false}; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
/*return new Material( |
|||
child: new SingleChildScrollView( |
|||
child: new Container( |
|||
width: 40.0, |
|||
height: 40.0, |
|||
constraints: BoxConstraints.tight(new Size(40, 300)), |
|||
color: AsScreenCanvas.CLColors.red, |
|||
child: new Center(child: new Text("XXXXXXXX")) |
|||
) |
|||
) |
|||
);*/ |
|||
return new Material( |
|||
child: new SingleChildScrollView( |
|||
child: new ExpansionPanelList( |
|||
expansionCallback: (int _index, bool _isExpanded) => { |
|||
Debug.Log("???????????" + _index + " <> " + _isExpanded); |
|||
|
|||
this.isExpand[_index] = !_isExpanded; |
|||
this.setState(() => {}); |
|||
}, |
|||
children: new List<ExpansionPanel> { |
|||
new ExpansionPanel( |
|||
headerBuilder: (BuildContext subContext, bool isExpanded) => { |
|||
return new Container( |
|||
width: 10.0, |
|||
height: 10.0, |
|||
constraints: BoxConstraints.tight(new Size(10, 10)), |
|||
color: AsScreenCanvas.CLColors.blue |
|||
); |
|||
}, |
|||
body: new Container( |
|||
width: 40.0, |
|||
height: 10.0, |
|||
constraints: BoxConstraints.tight(new Size(40, 10)), |
|||
color: AsScreenCanvas.CLColors.red |
|||
), |
|||
isExpanded : this.isExpand[0] |
|||
), |
|||
new ExpansionPanel( |
|||
headerBuilder: (BuildContext subContext, bool isExpanded) => { |
|||
return new Container( |
|||
width: 10.0, |
|||
height: 10.0, |
|||
constraints: BoxConstraints.tight(new Size(10, 10)), |
|||
color: AsScreenCanvas.CLColors.blue |
|||
); |
|||
}, |
|||
body: new Container( |
|||
width: 40.0, |
|||
height: 10.0, |
|||
constraints: BoxConstraints.tight(new Size(40, 10)), |
|||
color: AsScreenCanvas.CLColors.red |
|||
), |
|||
isExpanded: this.isExpand[1] |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 7b7c8f92f79054eb6ae6e6749ebec2a1 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue