您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

1347 行
51 KiB

using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.cupertino {
class CupertinoDialogUtils {
public static readonly TextStyle _kCupertinoDialogTitleStyle = new TextStyle(
fontFamily: ".SF UI Display",
fontSize: 18.0f,
fontWeight: FontWeight.w600,
color: CupertinoColors.black,
letterSpacing: 0.48f,
textBaseline: TextBaseline.alphabetic
);
public static readonly TextStyle _kCupertinoDialogContentStyle = new TextStyle(
fontFamily: ".SF UI Text",
fontSize: 13.4f,
fontWeight: FontWeight.w400,
color: CupertinoColors.black,
height: 1.036f,
letterSpacing: -0.25f,
textBaseline: TextBaseline.alphabetic
);
public static readonly TextStyle _kCupertinoDialogActionStyle = new TextStyle(
fontFamily: ".SF UI Text",
fontSize: 16.8f,
fontWeight: FontWeight.w400,
color: CupertinoColors.activeBlue,
textBaseline: TextBaseline.alphabetic
);
public const float _kCupertinoDialogWidth = 270.0f;
public const float _kAccessibilityCupertinoDialogWidth = 310.0f;
public static readonly BoxDecoration _kCupertinoDialogBlurOverlayDecoration = new BoxDecoration(
color: CupertinoColors.white,
backgroundBlendMode: BlendMode.overlay
);
public const float _kBlurAmount = 20.0f;
public const float _kEdgePadding = 20.0f;
public const float _kMinButtonHeight = 45.0f;
public const float _kMinButtonFontSize = 10.0f;
public const float _kDialogCornerRadius = 12.0f;
public const float _kDividerThickness = 1.0f;
public const float _kMaxRegularTextScaleFactor = 1.4f;
public static readonly Color _kDialogColor = new Color(0xC0FFFFFF);
public static readonly Color _kDialogPressedColor = new Color(0x90FFFFFF);
public static readonly Color _kButtonDividerColor = new Color(0x40FFFFFF);
public static bool _isInAccessibilityMode(BuildContext context) {
MediaQueryData data = MediaQuery.of(context, nullOk: true);
return data != null && data.textScaleFactor > _kMaxRegularTextScaleFactor;
}
}
public class CupertinoAlertDialog : StatelessWidget {
public CupertinoAlertDialog(
Key key = null,
Widget title = null,
Widget content = null,
List<Widget> actions = null,
ScrollController scrollController = null,
ScrollController actionScrollController = null
) : base(key: key) {
D.assert(actions != null);
this.title = title;
this.content = content;
this.actions = actions ?? new List<Widget>();
this.scrollController = scrollController;
this.actionScrollController = actionScrollController;
}
public readonly Widget title;
public readonly Widget content;
public readonly List<Widget> actions;
public readonly ScrollController scrollController;
public readonly ScrollController actionScrollController;
Widget _buildContent() {
List<Widget> children = new List<Widget>();
if (title != null || content != null) {
Widget titleSection = new _CupertinoDialogAlertContentSection(
title: title,
content: content,
scrollController: scrollController
);
children.Add(new Flexible(flex: 3, child: titleSection));
}
return new Container(
color: CupertinoDialogUtils._kDialogColor,
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children
)
);
}
Widget _buildActions() {
Widget actionSection = new Container(
height: 0.0f
);
if (actions.isNotEmpty()) {
actionSection = new _CupertinoDialogAlertActionSection(
children: actions,
scrollController: actionScrollController
);
}
return actionSection;
}
public override Widget build(BuildContext context) {
CupertinoLocalizations localizations = CupertinoLocalizations.of(context);
bool isInAccessibilityMode = CupertinoDialogUtils._isInAccessibilityMode(context);
float textScaleFactor = MediaQuery.of(context).textScaleFactor;
return new MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: Mathf.Max(textScaleFactor, 1.0f)
),
child: new LayoutBuilder(
builder: (BuildContext _context, BoxConstraints constraints) => {
return new Center(
child: new Container(
margin: EdgeInsets.symmetric(vertical: CupertinoDialogUtils._kEdgePadding),
width: isInAccessibilityMode
? CupertinoDialogUtils._kAccessibilityCupertinoDialogWidth
: CupertinoDialogUtils._kCupertinoDialogWidth,
child: new CupertinoPopupSurface(
isSurfacePainted: false,
child: new _CupertinoDialogRenderWidget(
contentSection: _buildContent(),
actionsSection: _buildActions()
)
)
)
);
}
)
);
}
}
public class CupertinoDialog : StatelessWidget {
public CupertinoDialog(
Key key = null,
Widget child = null
) : base(key: key) {
this.child = child;
}
public readonly Widget child;
public override Widget build(BuildContext context) {
return new Center(
child: new SizedBox(
width: CupertinoDialogUtils._kCupertinoDialogWidth,
child: new CupertinoPopupSurface(
child: child
)
)
);
}
}
public class CupertinoPopupSurface : StatelessWidget {
public CupertinoPopupSurface(
Key key = null,
bool isSurfacePainted = true,
Widget child = null
) : base(key: key) {
this.isSurfacePainted = isSurfacePainted;
this.child = child;
}
public readonly bool isSurfacePainted;
public readonly Widget child;
public override Widget build(BuildContext context) {
return new ClipRRect(
borderRadius: BorderRadius.circular(CupertinoDialogUtils._kDialogCornerRadius),
child: new BackdropFilter(
filter: ImageFilter.blur(sigmaX: CupertinoDialogUtils._kBlurAmount,
sigmaY: CupertinoDialogUtils._kBlurAmount),
child: new Container(
decoration: CupertinoDialogUtils._kCupertinoDialogBlurOverlayDecoration,
child: new Container(
color: isSurfacePainted ? CupertinoDialogUtils._kDialogColor : null,
child: child
)
)
)
);
}
}
class _CupertinoDialogRenderWidget : RenderObjectWidget {
public _CupertinoDialogRenderWidget(
Widget contentSection,
Widget actionsSection,
Key key = null
) : base(key: key) {
this.contentSection = contentSection;
this.actionsSection = actionsSection;
}
public readonly Widget contentSection;
public readonly Widget actionsSection;
public override RenderObject createRenderObject(BuildContext context) {
return new _RenderCupertinoDialog(
dividerThickness: CupertinoDialogUtils._kDividerThickness / MediaQuery.of(context).devicePixelRatio,
isInAccessibilityMode: CupertinoDialogUtils._isInAccessibilityMode(context)
);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
((_RenderCupertinoDialog) renderObject).isInAccessibilityMode =
CupertinoDialogUtils._isInAccessibilityMode(context);
}
public override Element createElement() {
return new _CupertinoDialogRenderElement(this);
}
}
class _CupertinoDialogRenderElement : RenderObjectElement {
public _CupertinoDialogRenderElement(_CupertinoDialogRenderWidget widget) : base(widget) {
}
Element _contentElement;
Element _actionsElement;
public new _CupertinoDialogRenderWidget widget {
get { return base.widget as _CupertinoDialogRenderWidget; }
}
public new _RenderCupertinoDialog renderObject {
get { return base.renderObject as _RenderCupertinoDialog; }
}
public override void visitChildren(ElementVisitor visitor) {
if (_contentElement != null) {
visitor(_contentElement);
}
if (_actionsElement != null) {
visitor(_actionsElement);
}
}
public override void mount(Element parent, object newSlot) {
base.mount(parent, newSlot);
_contentElement = updateChild(_contentElement, widget.contentSection,
_AlertDialogSections.contentSection);
_actionsElement = updateChild(_actionsElement, widget.actionsSection,
_AlertDialogSections.actionsSection);
}
protected override void insertChildRenderObject(RenderObject child, object slot) {
D.assert(slot != null);
switch (slot) {
case _AlertDialogSections.contentSection:
renderObject.contentSection = child as RenderBox;
break;
case _AlertDialogSections.actionsSection:
renderObject.actionsSection = child as RenderBox;
;
break;
}
}
protected override void moveChildRenderObject(RenderObject child, object slot) {
D.assert(false);
}
public override void update(Widget newWidget) {
base.update(newWidget);
_contentElement = updateChild(_contentElement, widget.contentSection,
_AlertDialogSections.contentSection);
_actionsElement = updateChild(_actionsElement, widget.actionsSection,
_AlertDialogSections.actionsSection);
}
protected override void forgetChild(Element child) {
D.assert(child == _contentElement || child == _actionsElement);
if (_contentElement == child) {
_contentElement = null;
}
else {
D.assert(_actionsElement == child);
_actionsElement = null;
}
}
protected override void removeChildRenderObject(RenderObject child) {
D.assert(child == renderObject.contentSection || child == renderObject.actionsSection);
if (renderObject.contentSection == child) {
renderObject.contentSection = null;
}
else {
D.assert(renderObject.actionsSection == child);
renderObject.actionsSection = null;
}
}
}
class _RenderCupertinoDialog : RenderBox {
public _RenderCupertinoDialog(
RenderBox contentSection = null,
RenderBox actionsSection = null,
float dividerThickness = 0.0f,
bool isInAccessibilityMode = false
) {
_contentSection = contentSection;
_actionsSection = actionsSection;
_dividerThickness = dividerThickness;
_isInAccessibilityMode = isInAccessibilityMode;
}
public RenderBox contentSection {
get { return _contentSection; }
set {
if (value != _contentSection) {
if (_contentSection != null) {
dropChild(_contentSection);
}
_contentSection = value;
if (_contentSection != null) {
adoptChild(_contentSection);
}
}
}
}
RenderBox _contentSection;
public RenderBox actionsSection {
get { return _actionsSection; }
set {
if (value != _actionsSection) {
if (null != _actionsSection) {
dropChild(_actionsSection);
}
_actionsSection = value;
if (null != _actionsSection) {
adoptChild(_actionsSection);
}
}
}
}
RenderBox _actionsSection;
public bool isInAccessibilityMode {
get { return _isInAccessibilityMode; }
set {
if (value != _isInAccessibilityMode) {
_isInAccessibilityMode = value;
markNeedsLayout();
}
}
}
bool _isInAccessibilityMode;
float _dialogWidth {
get {
return isInAccessibilityMode
? CupertinoDialogUtils._kAccessibilityCupertinoDialogWidth
: CupertinoDialogUtils._kCupertinoDialogWidth;
}
}
readonly float _dividerThickness;
readonly Paint _dividerPaint = new Paint() {
color = CupertinoDialogUtils._kButtonDividerColor,
style = PaintingStyle.fill
};
public override void attach(object owner) {
base.attach(owner);
if (null != contentSection) {
contentSection.attach(owner);
}
if (null != actionsSection) {
actionsSection.attach(owner);
}
}
public override void detach() {
base.detach();
if (null != contentSection) {
contentSection.detach();
}
if (null != actionsSection) {
actionsSection.detach();
}
}
public override void redepthChildren() {
if (null != contentSection) {
redepthChild(contentSection);
}
if (null != actionsSection) {
redepthChild(actionsSection);
}
}
public override void setupParentData(RenderObject child) {
if (!(child.parentData is BoxParentData)) {
child.parentData = new BoxParentData();
}
}
public override void visitChildren(RenderObjectVisitor visitor) {
if (contentSection != null) {
visitor(contentSection);
}
if (actionsSection != null) {
visitor(actionsSection);
}
}
public override List<DiagnosticsNode> debugDescribeChildren() {
List<DiagnosticsNode> value = new List<DiagnosticsNode>();
if (contentSection != null) {
value.Add(contentSection.toDiagnosticsNode(name: "content"));
}
if (actionsSection != null) {
value.Add(actionsSection.toDiagnosticsNode(name: "actions"));
}
return value;
}
protected override float computeMinIntrinsicWidth(float height) {
return _dialogWidth;
}
protected override float computeMaxIntrinsicWidth(float height) {
return _dialogWidth;
}
protected override float computeMinIntrinsicHeight(float width) {
float contentHeight = contentSection.getMinIntrinsicHeight(width);
float actionsHeight = actionsSection.getMinIntrinsicHeight(width);
bool hasDivider = contentHeight > 0.0f && actionsHeight > 0.0f;
float height = contentHeight + (hasDivider ? _dividerThickness : 0.0f) + actionsHeight;
if (height.isFinite()) {
return height;
}
return 0.0f;
}
protected internal override float computeMaxIntrinsicHeight(float width) {
float contentHeight = contentSection.getMaxIntrinsicHeight(width);
float actionsHeight = actionsSection.getMaxIntrinsicHeight(width);
bool hasDivider = contentHeight > 0.0f && actionsHeight > 0.0f;
float height = contentHeight + (hasDivider ? _dividerThickness : 0.0f) + actionsHeight;
if (height.isFinite()) {
return height;
}
return 0.0f;
}
protected override void performLayout() {
if (isInAccessibilityMode) {
performAccessibilityLayout();
}
else {
performRegularLayout();
}
}
void performRegularLayout() {
bool hasDivider = contentSection.getMaxIntrinsicHeight(_dialogWidth) > 0.0f
&& actionsSection.getMaxIntrinsicHeight(_dialogWidth) > 0.0f;
float dividerThickness = hasDivider ? _dividerThickness : 0.0f;
float minActionsHeight = actionsSection.getMinIntrinsicHeight(_dialogWidth);
contentSection.layout(
constraints.deflate(EdgeInsets.only(bottom: minActionsHeight + dividerThickness)),
parentUsesSize: true
);
Size contentSize = contentSection.size;
actionsSection.layout(
constraints.deflate(EdgeInsets.only(top: contentSize.height + dividerThickness)),
parentUsesSize: true
);
Size actionsSize = actionsSection.size;
float dialogHeight = contentSize.height + dividerThickness + actionsSize.height;
size = constraints.constrain(
new Size(_dialogWidth, dialogHeight)
);
D.assert(actionsSection.parentData is BoxParentData);
BoxParentData actionParentData = actionsSection.parentData as BoxParentData;
actionParentData.offset = new Offset(0.0f, contentSize.height + dividerThickness);
}
void performAccessibilityLayout() {
bool hasDivider = contentSection.getMaxIntrinsicHeight(_dialogWidth) > 0.0f
&& actionsSection.getMaxIntrinsicHeight(_dialogWidth) > 0.0f;
float dividerThickness = hasDivider ? _dividerThickness : 0.0f;
float maxContentHeight = contentSection.getMaxIntrinsicHeight(_dialogWidth);
float maxActionsHeight = actionsSection.getMaxIntrinsicHeight(_dialogWidth);
Size contentSize;
Size actionsSize;
if (maxContentHeight + dividerThickness + maxActionsHeight > constraints.maxHeight) {
actionsSection.layout(
constraints.deflate(EdgeInsets.only(top: constraints.maxHeight / 2.0f)),
parentUsesSize: true
);
actionsSize = actionsSection.size;
contentSection.layout(
constraints.deflate(EdgeInsets.only(bottom: actionsSize.height + dividerThickness)),
parentUsesSize: true
);
contentSize = contentSection.size;
}
else {
contentSection.layout(constraints,
parentUsesSize: true
);
contentSize = contentSection.size;
actionsSection.layout(constraints.deflate(EdgeInsets.only(top: contentSize.height)),
parentUsesSize: true
);
actionsSize = actionsSection.size;
}
float dialogHeight = contentSize.height + dividerThickness + actionsSize.height;
size = constraints.constrain(
new Size(_dialogWidth, dialogHeight)
);
D.assert(actionsSection.parentData is BoxParentData);
BoxParentData actionParentData = actionsSection.parentData as BoxParentData;
actionParentData.offset = new Offset(0.0f, contentSize.height + dividerThickness);
}
public override void paint(PaintingContext context, Offset offset) {
BoxParentData contentParentData = contentSection.parentData as BoxParentData;
contentSection.paint(context, offset + contentParentData.offset);
bool hasDivider = contentSection.size.height > 0.0f && actionsSection.size.height > 0.0f;
if (hasDivider) {
_paintDividerBetweenContentAndActions(context.canvas, offset);
}
BoxParentData actionsParentData = actionsSection.parentData as BoxParentData;
actionsSection.paint(context, offset + actionsParentData.offset);
}
void _paintDividerBetweenContentAndActions(Canvas canvas, Offset offset) {
canvas.drawRect(
Rect.fromLTWH(
offset.dx,
offset.dy + contentSection.size.height, size.width, _dividerThickness
), _dividerPaint
);
}
protected override bool hitTestChildren(BoxHitTestResult result, Offset position = null
) {
BoxParentData contentSectionParentData = contentSection.parentData as BoxParentData;
BoxParentData actionsSectionParentData = actionsSection.parentData as BoxParentData;
return result.addWithPaintOffset(
offset: contentSectionParentData.offset,
position: position,
hitTest: (BoxHitTestResult resultIn, Offset transformed) => {
D.assert(transformed == position - contentSectionParentData.offset);
return contentSection.hitTest(resultIn, position: transformed);
}
) || result.addWithPaintOffset(
offset: actionsSectionParentData.offset,
position: position,
hitTest: (BoxHitTestResult resultIn, Offset transformed) => {
D.assert(transformed == position - actionsSectionParentData.offset);
return actionsSection.hitTest(resultIn, position: transformed);
}
);
}
}
enum _AlertDialogSections {
contentSection,
actionsSection,
}
class _CupertinoDialogAlertContentSection : StatelessWidget {
public _CupertinoDialogAlertContentSection(
Key key = null,
Widget title = null,
Widget content = null,
ScrollController scrollController = null
) : base(key: key) {
this.title = title;
this.content = content;
this.scrollController = scrollController;
}
public readonly Widget title;
public readonly Widget content;
public readonly ScrollController scrollController;
public override Widget build(BuildContext context) {
float textScaleFactor = MediaQuery.of(context).textScaleFactor;
List<Widget> titleContentGroup = new List<Widget>();
if (title != null) {
titleContentGroup.Add(new Padding(
padding: EdgeInsets.only(
left: CupertinoDialogUtils._kEdgePadding,
right: CupertinoDialogUtils._kEdgePadding,
bottom: content == null ? CupertinoDialogUtils._kEdgePadding : 1.0f,
top: CupertinoDialogUtils._kEdgePadding * textScaleFactor
),
child: new DefaultTextStyle(
style: CupertinoDialogUtils._kCupertinoDialogTitleStyle,
textAlign: TextAlign.center,
child: title
)
));
}
if (content != null) {
titleContentGroup.Add(
new Padding(
padding: EdgeInsets.only(
left: CupertinoDialogUtils._kEdgePadding,
right: CupertinoDialogUtils._kEdgePadding,
bottom: CupertinoDialogUtils._kEdgePadding * textScaleFactor,
top: title == null ? CupertinoDialogUtils._kEdgePadding : 1.0f
),
child: new DefaultTextStyle(
style: CupertinoDialogUtils._kCupertinoDialogContentStyle,
textAlign: TextAlign.center,
child: content
)
)
);
}
if (titleContentGroup.isEmpty()) {
return new SingleChildScrollView(
controller: scrollController,
child: new Container(width: 0.0f, height: 0.0f)
);
}
return new CupertinoScrollbar(
child: new SingleChildScrollView(
controller: scrollController,
child: new Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: titleContentGroup
)
)
);
}
}
class _CupertinoDialogAlertActionSection : StatefulWidget {
public _CupertinoDialogAlertActionSection(
List<Widget> children,
Key key = null,
ScrollController scrollController = null
) : base(key: key) {
D.assert(children != null);
this.children = children;
this.scrollController = scrollController;
}
public readonly List<Widget> children;
public readonly ScrollController scrollController;
public override State createState() {
return new _CupertinoDialogAlertActionSectionState();
}
}
class _CupertinoDialogAlertActionSectionState : State<_CupertinoDialogAlertActionSection> {
public override Widget build(BuildContext context) {
float devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
List<Widget> interactiveButtons = new List<Widget>();
for (int i = 0; i < widget.children.Count; i += 1) {
interactiveButtons.Add(
new _PressableDialogActionButton(
child: widget.children[i]
)
);
}
return new CupertinoScrollbar(
child: new SingleChildScrollView(
controller: widget.scrollController,
child: new _CupertinoDialogActionsRenderWidget(
actionButtons: interactiveButtons,
dividerThickness: CupertinoDialogUtils._kDividerThickness / devicePixelRatio
)
)
);
}
}
class _PressableDialogActionButton : StatefulWidget {
public _PressableDialogActionButton(
Widget child
) {
this.child = child;
}
public readonly Widget child;
public override State createState() {
return new _PressableDialogActionButtonState();
}
}
class _PressableDialogActionButtonState : State<_PressableDialogActionButton> {
bool _isPressed = false;
public override Widget build(BuildContext context) {
return new _DialogActionButtonParentDataWidget(
isPressed: _isPressed,
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (TapDownDetails details) => setState(() => { _isPressed = true; }),
onTapUp: (TapUpDetails details) => setState(() => { _isPressed = false; }),
onTapCancel: () => setState(() => _isPressed = false),
child: widget.child
)
);
}
}
class _DialogActionButtonParentDataWidget : ParentDataWidget<_CupertinoDialogActionsRenderWidget> {
public _DialogActionButtonParentDataWidget(
Widget child,
bool isPressed = false,
Key key = null
) : base(key: key, child: child) {
this.isPressed = isPressed;
}
public readonly bool isPressed;
public override void applyParentData(RenderObject renderObject) {
D.assert(renderObject.parentData is _DialogActionButtonParentData);
_DialogActionButtonParentData parentData = renderObject.parentData as _DialogActionButtonParentData;
if (parentData.isPressed != isPressed) {
parentData.isPressed = isPressed;
AbstractNodeMixinDiagnosticableTree targetParent = renderObject.parent;
if (targetParent is RenderObject) {
((RenderObject) targetParent).markNeedsPaint();
}
}
}
}
class _DialogActionButtonParentData : MultiChildLayoutParentData {
public _DialogActionButtonParentData(
bool isPressed = false
) {
this.isPressed = isPressed;
}
public bool isPressed;
}
public class CupertinoDialogAction : StatelessWidget {
public CupertinoDialogAction(
Widget child,
VoidCallback onPressed = null,
bool isDefaultAction = false,
bool isDestructiveAction = false,
TextStyle textStyle = null
) {
D.assert(child != null);
this.onPressed = onPressed;
this.isDefaultAction = isDefaultAction;
this.isDestructiveAction = isDestructiveAction;
this.textStyle = textStyle;
this.child = child;
}
public readonly VoidCallback onPressed;
public readonly bool isDefaultAction;
public readonly bool isDestructiveAction;
public readonly TextStyle textStyle;
public readonly Widget child;
public bool enabled {
get { return onPressed != null; }
}
float _calculatePadding(BuildContext context) {
return 8.0f * MediaQuery.textScaleFactorOf(context);
}
Widget _buildContentWithRegularSizingPolicy(
BuildContext context,
TextStyle textStyle,
Widget content
) {
bool isInAccessibilityMode = CupertinoDialogUtils._isInAccessibilityMode(context);
float dialogWidth = isInAccessibilityMode
? CupertinoDialogUtils._kAccessibilityCupertinoDialogWidth
: CupertinoDialogUtils._kCupertinoDialogWidth;
float textScaleFactor = MediaQuery.textScaleFactorOf(context);
float fontSizeRatio =
(textScaleFactor * textStyle.fontSize) / CupertinoDialogUtils._kMinButtonFontSize ?? 0f;
float padding = _calculatePadding(context);
return new IntrinsicHeight(
child: new SizedBox(
width: float.PositiveInfinity,
child: new FittedBox(
fit: BoxFit.scaleDown,
child: new ConstrainedBox(
constraints: new BoxConstraints(
maxWidth: fontSizeRatio * (dialogWidth - (2 * padding))
),
child: new DefaultTextStyle(
style: textStyle,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
maxLines: 1,
child: content
)
)
)
)
);
}
Widget _buildContentWithAccessibilitySizingPolicy(
TextStyle textStyle,
Widget content
) {
return new DefaultTextStyle(
style: textStyle,
textAlign: TextAlign.center,
child: content
);
}
public override Widget build(BuildContext context) {
TextStyle style = CupertinoDialogUtils._kCupertinoDialogActionStyle;
style = style.merge(textStyle);
if (isDestructiveAction) {
style = style.copyWith(color: CupertinoColors.destructiveRed);
}
if (!enabled) {
style = style.copyWith(color: style.color.withOpacity(0.5f));
}
Widget sizedContent = CupertinoDialogUtils._isInAccessibilityMode(context)
? _buildContentWithAccessibilitySizingPolicy(
textStyle: style,
content: child
)
: _buildContentWithRegularSizingPolicy(
context: context,
textStyle: style,
content: child
);
return new GestureDetector(
onTap: () => onPressed(),
behavior: HitTestBehavior.opaque,
child: new ConstrainedBox(
constraints: new BoxConstraints(
minHeight: CupertinoDialogUtils._kMinButtonHeight
),
child: new Container(
alignment: Alignment.center,
padding: EdgeInsets.all(_calculatePadding(context)),
child: sizedContent
)
)
);
}
}
class _CupertinoDialogActionsRenderWidget : MultiChildRenderObjectWidget {
public _CupertinoDialogActionsRenderWidget(
List<Widget> actionButtons,
Key key = null,
float dividerThickness = 0.0f
) : base(key: key, children: actionButtons) {
_dividerThickness = dividerThickness;
}
public readonly float _dividerThickness;
public override RenderObject createRenderObject(BuildContext context) {
return new _RenderCupertinoDialogActions(
dialogWidth: CupertinoDialogUtils._isInAccessibilityMode(context)
? CupertinoDialogUtils._kAccessibilityCupertinoDialogWidth
: CupertinoDialogUtils._kCupertinoDialogWidth,
dividerThickness: _dividerThickness
);
}
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
(renderObject as _RenderCupertinoDialogActions).dialogWidth =
CupertinoDialogUtils._isInAccessibilityMode(context)
? CupertinoDialogUtils._kAccessibilityCupertinoDialogWidth
: CupertinoDialogUtils._kCupertinoDialogWidth;
(renderObject as _RenderCupertinoDialogActions).dividerThickness = _dividerThickness;
}
}
class _RenderCupertinoDialogActions : RenderBoxContainerDefaultsMixinContainerRenderObjectMixinRenderBox<
RenderBox, MultiChildLayoutParentData> {
public _RenderCupertinoDialogActions(
float dialogWidth,
List<RenderBox> children = null,
float dividerThickness = 0.0f
) {
_dialogWidth = dialogWidth;
_dividerThickness = dividerThickness;
addAll(children);
}
public float dialogWidth {
get { return _dialogWidth; }
set {
if (value != _dialogWidth) {
_dialogWidth = value;
markNeedsLayout();
}
}
}
float _dialogWidth;
public float dividerThickness {
get { return _dividerThickness; }
set {
if (value != _dividerThickness) {
_dividerThickness = value;
markNeedsLayout();
}
}
}
float _dividerThickness;
readonly Paint _buttonBackgroundPaint = new Paint() {
color = CupertinoDialogUtils._kDialogColor,
style = PaintingStyle.fill
};
readonly Paint _pressedButtonBackgroundPaint = new Paint() {
color = CupertinoDialogUtils._kDialogPressedColor,
style = PaintingStyle.fill
};
readonly Paint _dividerPaint = new Paint() {
color = CupertinoDialogUtils._kButtonDividerColor,
style = PaintingStyle.fill
};
List<RenderBox> _pressedButtons {
get {
List<RenderBox> childList = new List<RenderBox>();
RenderBox currentChild = firstChild;
while (currentChild != null) {
D.assert(currentChild.parentData is _DialogActionButtonParentData);
_DialogActionButtonParentData parentData = currentChild.parentData as _DialogActionButtonParentData;
if (parentData.isPressed) {
childList.Add(currentChild);
}
currentChild = childAfter(currentChild);
}
return childList;
}
}
bool _isButtonPressed {
get {
RenderBox currentChild = firstChild;
while (currentChild != null) {
D.assert(currentChild.parentData is _DialogActionButtonParentData);
_DialogActionButtonParentData parentData = currentChild.parentData as _DialogActionButtonParentData;
if (parentData.isPressed) {
return true;
}
currentChild = childAfter(currentChild);
}
return false;
}
}
public override void setupParentData(RenderObject child) {
if (!(child.parentData is _DialogActionButtonParentData)) {
child.parentData = new _DialogActionButtonParentData();
}
}
protected override float computeMinIntrinsicWidth(float height) {
return dialogWidth;
}
protected override float computeMaxIntrinsicWidth(float height) {
return dialogWidth;
}
protected override float computeMinIntrinsicHeight(float width) {
float minHeight;
if (childCount == 0) {
minHeight = 0.0f;
}
else if (childCount == 1) {
minHeight = _computeMinIntrinsicHeightSideBySide(width);
}
else {
if (childCount == 2 && _isSingleButtonRow(width)) {
minHeight = _computeMinIntrinsicHeightSideBySide(width);
}
else {
minHeight = _computeMinIntrinsicHeightStacked(width);
}
}
return minHeight;
}
float _computeMinIntrinsicHeightSideBySide(float width) {
D.assert(childCount >= 1 && childCount <= 2);
float minHeight;
if (childCount == 1) {
minHeight = firstChild.getMinIntrinsicHeight(width);
}
else {
float perButtonWidth = (width - dividerThickness) / 2.0f;
minHeight = Mathf.Max(firstChild.getMinIntrinsicHeight(perButtonWidth),
lastChild.getMinIntrinsicHeight(perButtonWidth)
);
}
return minHeight;
}
float _computeMinIntrinsicHeightStacked(float width) {
D.assert(childCount >= 2);
return firstChild.getMinIntrinsicHeight(width)
+ dividerThickness
+ (0.5f * childAfter(firstChild).getMinIntrinsicHeight(width));
}
protected internal override float computeMaxIntrinsicHeight(float width) {
float maxHeight;
if (childCount == 0) {
maxHeight = 0.0f;
}
else if (childCount == 1) {
maxHeight = firstChild.getMaxIntrinsicHeight(width);
}
else if (childCount == 2) {
if (_isSingleButtonRow(width)) {
float perButtonWidth = (width - dividerThickness) / 2.0f;
maxHeight = Mathf.Max(firstChild.getMaxIntrinsicHeight(perButtonWidth),
lastChild.getMaxIntrinsicHeight(perButtonWidth)
);
}
else {
maxHeight = _computeMaxIntrinsicHeightStacked(width);
}
}
else {
maxHeight = _computeMaxIntrinsicHeightStacked(width);
}
return maxHeight;
}
float _computeMaxIntrinsicHeightStacked(float width) {
D.assert(childCount >= 2);
float allDividersHeight = (childCount - 1) * dividerThickness;
float heightAccumulation = allDividersHeight;
RenderBox button = firstChild;
while (button != null) {
heightAccumulation += button.getMaxIntrinsicHeight(width);
button = childAfter(button);
}
return heightAccumulation;
}
bool _isSingleButtonRow(float width) {
bool isSingleButtonRow;
if (childCount == 1) {
isSingleButtonRow = true;
}
else if (childCount == 2) {
float sideBySideWidth = firstChild.getMaxIntrinsicWidth(float.PositiveInfinity)
+ dividerThickness
+ lastChild.getMaxIntrinsicWidth(float.PositiveInfinity);
isSingleButtonRow = sideBySideWidth <= width;
}
else {
isSingleButtonRow = false;
}
return isSingleButtonRow;
}
protected override void performLayout() {
if (_isSingleButtonRow(dialogWidth)) {
if (childCount == 1) {
firstChild.layout(
constraints,
parentUsesSize: true
);
size = constraints.constrain(
new Size(dialogWidth, firstChild.size.height)
);
}
else {
BoxConstraints perButtonnewraints = new BoxConstraints(
minWidth: (constraints.minWidth - dividerThickness) / 2.0f,
maxWidth: (constraints.maxWidth - dividerThickness) / 2.0f,
minHeight: 0.0f,
maxHeight: float.PositiveInfinity
);
firstChild.layout(
perButtonnewraints,
parentUsesSize: true
);
lastChild.layout(
perButtonnewraints,
parentUsesSize: true
);
D.assert(lastChild.parentData is MultiChildLayoutParentData);
MultiChildLayoutParentData secondButtonParentData =
lastChild.parentData as MultiChildLayoutParentData;
secondButtonParentData.offset =
new Offset(firstChild.size.width + dividerThickness, 0.0f);
size = constraints.constrain(
new Size(dialogWidth,
Mathf.Max(firstChild.size.height, lastChild.size.height
)
)
);
}
}
else {
BoxConstraints perButtonnewraints = constraints.copyWith(
minHeight: 0.0f,
maxHeight: float.PositiveInfinity
);
RenderBox child = firstChild;
int index = 0;
float verticalOffset = 0.0f;
while (child != null) {
child.layout(
perButtonnewraints,
parentUsesSize: true
);
D.assert(child.parentData is MultiChildLayoutParentData);
MultiChildLayoutParentData parentData = child.parentData as MultiChildLayoutParentData;
parentData.offset = new Offset(0.0f, verticalOffset);
verticalOffset += child.size.height;
if (index < childCount - 1) {
verticalOffset += dividerThickness;
}
index += 1;
child = childAfter(child);
}
size = constraints.constrain(
new Size(dialogWidth, verticalOffset)
);
}
}
public override void paint(PaintingContext context, Offset offset) {
Canvas canvas = context.canvas;
if (_isSingleButtonRow(size.width)) {
_drawButtonBackgroundsAndDividersSingleRow(canvas, offset);
}
else {
_drawButtonBackgroundsAndDividersStacked(canvas, offset);
}
_drawButtons(context, offset);
}
void _drawButtonBackgroundsAndDividersSingleRow(Canvas canvas, Offset offset) {
Rect verticalDivider = childCount == 2 && !_isButtonPressed
? Rect.fromLTWH(
offset.dx + firstChild.size.width,
offset.dy, dividerThickness,
Mathf.Max(firstChild.size.height, lastChild.size.height
)
)
: Rect.zero;
List<Rect> pressedButtonRects = new List<Rect>();
foreach (var item in _pressedButtons) {
MultiChildLayoutParentData buttonParentData = item.parentData as MultiChildLayoutParentData;
pressedButtonRects.Add(
Rect.fromLTWH(
offset.dx + buttonParentData.offset.dx,
offset.dy + buttonParentData.offset.dy,
item.size.width,
item.size.height
));
}
Path backgroundFillPath = new Path();
// backgroundFillPath.fillType = PathFillType.evenOdd;
backgroundFillPath.addRect(Rect.fromLTWH(0.0f, 0.0f, size.width, size.height));
backgroundFillPath.addRect(verticalDivider);
for (int i = 0; i < pressedButtonRects.Count; i += 1) {
backgroundFillPath.addRect(pressedButtonRects[i]);
}
canvas.drawPath(
backgroundFillPath, _buttonBackgroundPaint
);
Path pressedBackgroundFillPath = new Path();
for (int i = 0; i < pressedButtonRects.Count; i += 1) {
pressedBackgroundFillPath.addRect(pressedButtonRects[i]);
}
canvas.drawPath(
pressedBackgroundFillPath, _pressedButtonBackgroundPaint
);
Path dividersPath = new Path();
dividersPath.addRect(verticalDivider);
canvas.drawPath(
dividersPath, _dividerPaint
);
}
void _drawButtonBackgroundsAndDividersStacked(Canvas canvas, Offset offset) {
Offset dividerOffset = new Offset(0.0f, dividerThickness);
Path backgroundFillPath = new Path();
// ..fillType = PathFillType.evenOdd
backgroundFillPath.addRect(Rect.fromLTWH(0.0f, 0.0f, size.width, size.height));
Path pressedBackgroundFillPath = new Path();
Path dividersPath = new Path();
Offset accumulatingOffset = offset;
RenderBox child = firstChild;
RenderBox prevChild = null;
while (child != null) {
D.assert(child.parentData is _DialogActionButtonParentData);
_DialogActionButtonParentData currentButtonParentData =
child.parentData as _DialogActionButtonParentData;
bool isButtonPressed = currentButtonParentData.isPressed;
bool isPrevButtonPressed = false;
if (prevChild != null) {
D.assert(prevChild.parentData is _DialogActionButtonParentData);
_DialogActionButtonParentData previousButtonParentData =
prevChild.parentData as _DialogActionButtonParentData;
isPrevButtonPressed = previousButtonParentData.isPressed;
}
bool isDividerPresent = child != firstChild;
bool isDividerPainted = isDividerPresent && !(isButtonPressed || isPrevButtonPressed);
Rect dividerRect = Rect.fromLTWH(
accumulatingOffset.dx,
accumulatingOffset.dy, size.width, dividerThickness
);
Rect buttonBackgroundRect = Rect.fromLTWH(
accumulatingOffset.dx,
accumulatingOffset.dy + (isDividerPresent ? dividerThickness : 0.0f), size.width,
child.size.height
);
if (isButtonPressed) {
backgroundFillPath.addRect(buttonBackgroundRect);
pressedBackgroundFillPath.addRect(buttonBackgroundRect);
}
if (isDividerPainted) {
backgroundFillPath.addRect(dividerRect);
dividersPath.addRect(dividerRect);
}
accumulatingOffset += (isDividerPresent ? dividerOffset : Offset.zero)
+ new Offset(0.0f, child.size.height);
prevChild = child;
child = childAfter(child);
}
canvas.drawPath(backgroundFillPath, _buttonBackgroundPaint);
canvas.drawPath(pressedBackgroundFillPath, _pressedButtonBackgroundPaint);
canvas.drawPath(dividersPath, _dividerPaint);
}
void _drawButtons(PaintingContext context, Offset offset) {
RenderBox child = firstChild;
while (child != null) {
MultiChildLayoutParentData childParentData = child.parentData as MultiChildLayoutParentData;
context.paintChild(child, childParentData.offset + offset);
child = childAfter(child);
}
}
protected override bool hitTestChildren(BoxHitTestResult result,
Offset position = null
) {
return defaultHitTestChildren(result, position: position);
}
}
}