您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
1011 行
41 KiB
1011 行
41 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
using UnityEngine;
|
|
using Color = Unity.UIWidgets.ui.Color;
|
|
using Rect = Unity.UIWidgets.ui.Rect;
|
|
using TextStyle = Unity.UIWidgets.painting.TextStyle;
|
|
|
|
namespace Unity.UIWidgets.material {
|
|
public delegate void ToggleButtonOnPressed(int index);
|
|
|
|
public class ToggleButtons : StatelessWidget {
|
|
public ToggleButtons(
|
|
Key key = null,
|
|
List<Widget> children = null,
|
|
List<bool> isSelected = null,
|
|
ToggleButtonOnPressed onPressed = null,
|
|
TextStyle textStyle = null,
|
|
BoxConstraints constraints = null,
|
|
Color color = null,
|
|
Color selectedColor = null,
|
|
Color disabledColor = null,
|
|
Color fillColor = null,
|
|
Color focusColor = null,
|
|
Color highlightColor = null,
|
|
Color hoverColor = null,
|
|
Color splashColor = null,
|
|
List<FocusNode> focusNodes = null,
|
|
bool renderBorder = false,
|
|
Color borderColor = null,
|
|
Color selectedBorderColor = null,
|
|
Color disabledBorderColor = null,
|
|
BorderRadius borderRadius = null,
|
|
float? borderWidth = null
|
|
) : base(key: key) {
|
|
D.assert(children != null);
|
|
D.assert(isSelected != null);
|
|
D.assert(children.Count == isSelected.Count);
|
|
|
|
this.children = children;
|
|
this.isSelected = isSelected;
|
|
this.onPressed = onPressed;
|
|
this.textStyle = textStyle;
|
|
this.constraints = constraints;
|
|
this.color = color;
|
|
this.selectedColor = selectedColor;
|
|
this.disabledColor = disabledColor;
|
|
this.fillColor = fillColor;
|
|
this.focusColor = focusColor;
|
|
this.highlightColor = highlightColor;
|
|
this.hoverColor = hoverColor;
|
|
this.splashColor = splashColor;
|
|
this.focusNodes = focusNodes;
|
|
this.renderBorder = renderBorder;
|
|
this.borderColor = borderColor;
|
|
this.selectedBorderColor = selectedBorderColor;
|
|
this.disabledBorderColor = disabledBorderColor;
|
|
this.borderRadius = borderRadius;
|
|
this.borderWidth = borderWidth;
|
|
}
|
|
|
|
const float _defaultBorderWidth = 1.0f;
|
|
|
|
public readonly List<Widget> children;
|
|
|
|
public readonly List<bool> isSelected;
|
|
|
|
public readonly ToggleButtonOnPressed onPressed;
|
|
|
|
public readonly TextStyle textStyle;
|
|
|
|
public readonly BoxConstraints constraints;
|
|
|
|
public readonly Color color;
|
|
|
|
public readonly Color selectedColor;
|
|
|
|
public readonly Color disabledColor;
|
|
|
|
public readonly Color fillColor;
|
|
|
|
public readonly Color focusColor;
|
|
|
|
public readonly Color highlightColor;
|
|
|
|
public readonly Color splashColor;
|
|
|
|
public readonly Color hoverColor;
|
|
|
|
public readonly List<FocusNode> focusNodes;
|
|
|
|
public readonly bool renderBorder;
|
|
|
|
public readonly Color borderColor;
|
|
|
|
public readonly Color selectedBorderColor;
|
|
|
|
public readonly Color disabledBorderColor;
|
|
|
|
public readonly float? borderWidth;
|
|
|
|
public readonly BorderRadius borderRadius;
|
|
|
|
bool _isFirstIndex(int index, int length, TextDirection textDirection) {
|
|
return index == 0 && textDirection == TextDirection.ltr
|
|
|| index == length - 1 && textDirection == TextDirection.rtl;
|
|
}
|
|
|
|
bool _isLastIndex(int index, int length, TextDirection textDirection) {
|
|
return index == length - 1 && textDirection == TextDirection.ltr
|
|
|| index == 0 && textDirection == TextDirection.rtl;
|
|
}
|
|
|
|
BorderRadius _getEdgeBorderRadius(
|
|
int index,
|
|
int length,
|
|
TextDirection textDirection,
|
|
ToggleButtonsThemeData toggleButtonsTheme
|
|
) {
|
|
BorderRadius resultingBorderRadius = borderRadius
|
|
?? toggleButtonsTheme.borderRadius
|
|
?? BorderRadius.zero;
|
|
|
|
if (_isFirstIndex(index, length, textDirection)) {
|
|
return BorderRadius.only(
|
|
topLeft: resultingBorderRadius.topLeft,
|
|
bottomLeft: resultingBorderRadius.bottomLeft
|
|
);
|
|
}
|
|
else if (_isLastIndex(index, length, textDirection)) {
|
|
return BorderRadius.only(
|
|
topRight: resultingBorderRadius.topRight,
|
|
bottomRight: resultingBorderRadius.bottomRight
|
|
);
|
|
}
|
|
|
|
return BorderRadius.zero;
|
|
}
|
|
|
|
BorderRadius _getClipBorderRadius(
|
|
int index,
|
|
int length,
|
|
TextDirection textDirection,
|
|
ToggleButtonsThemeData toggleButtonsTheme
|
|
) {
|
|
BorderRadius resultingBorderRadius = borderRadius
|
|
?? toggleButtonsTheme.borderRadius
|
|
?? BorderRadius.zero;
|
|
float resultingBorderWidth = borderWidth
|
|
?? toggleButtonsTheme.borderWidth
|
|
?? _defaultBorderWidth;
|
|
|
|
if (_isFirstIndex(index, length, textDirection)) {
|
|
return BorderRadius.only(
|
|
topLeft: resultingBorderRadius.topLeft - Radius.circular(resultingBorderWidth / 2.0f),
|
|
bottomLeft: resultingBorderRadius.bottomLeft - Radius.circular(resultingBorderWidth / 2.0f)
|
|
);
|
|
}
|
|
else if (_isLastIndex(index, length, textDirection)) {
|
|
return BorderRadius.only(
|
|
topRight: resultingBorderRadius.topRight - Radius.circular(resultingBorderWidth / 2.0f),
|
|
bottomRight: resultingBorderRadius.bottomRight - Radius.circular(resultingBorderWidth / 2.0f)
|
|
);
|
|
}
|
|
|
|
return BorderRadius.zero;
|
|
}
|
|
|
|
BorderSide _getLeadingBorderSide(
|
|
int index,
|
|
ThemeData theme,
|
|
ToggleButtonsThemeData toggleButtonsTheme
|
|
) {
|
|
if (!renderBorder) {
|
|
return BorderSide.none;
|
|
}
|
|
|
|
float resultingBorderWidth = borderWidth
|
|
?? toggleButtonsTheme.borderWidth
|
|
?? _defaultBorderWidth;
|
|
if (onPressed != null && (isSelected[index] || (index != 0 && isSelected[index - 1]))) {
|
|
return new BorderSide(
|
|
color: selectedBorderColor
|
|
?? toggleButtonsTheme.selectedBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else if (onPressed != null && !isSelected[index]) {
|
|
return new BorderSide(
|
|
color: borderColor
|
|
?? toggleButtonsTheme.borderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else {
|
|
return new BorderSide(
|
|
color: disabledBorderColor
|
|
?? toggleButtonsTheme.disabledBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
}
|
|
|
|
BorderSide _getHorizontalBorderSide(
|
|
int index,
|
|
ThemeData theme,
|
|
ToggleButtonsThemeData toggleButtonsTheme
|
|
) {
|
|
if (!renderBorder) {
|
|
return BorderSide.none;
|
|
}
|
|
|
|
float resultingBorderWidth = borderWidth
|
|
?? toggleButtonsTheme.borderWidth
|
|
?? _defaultBorderWidth;
|
|
if (onPressed != null && isSelected[index]) {
|
|
return new BorderSide(
|
|
color: selectedBorderColor
|
|
?? toggleButtonsTheme.selectedBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else if (onPressed != null && !isSelected[index]) {
|
|
return new BorderSide(
|
|
color: borderColor
|
|
?? toggleButtonsTheme.borderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else {
|
|
return new BorderSide(
|
|
color: disabledBorderColor
|
|
?? toggleButtonsTheme.disabledBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
}
|
|
|
|
BorderSide _getTrailingBorderSide(
|
|
int index,
|
|
ThemeData theme,
|
|
ToggleButtonsThemeData toggleButtonsTheme
|
|
) {
|
|
if (!renderBorder) {
|
|
return BorderSide.none;
|
|
}
|
|
|
|
if (index != children.Count - 1) {
|
|
return null;
|
|
}
|
|
|
|
float resultingBorderWidth = borderWidth
|
|
?? toggleButtonsTheme.borderWidth
|
|
?? _defaultBorderWidth;
|
|
if (onPressed != null && (isSelected[index])) {
|
|
return new BorderSide(
|
|
color: selectedBorderColor
|
|
?? toggleButtonsTheme.selectedBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else if (onPressed != null && !isSelected[index]) {
|
|
return new BorderSide(
|
|
color: borderColor
|
|
?? toggleButtonsTheme.borderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
else {
|
|
return new BorderSide(
|
|
color: disabledBorderColor
|
|
?? toggleButtonsTheme.disabledBorderColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f),
|
|
width: resultingBorderWidth
|
|
);
|
|
}
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
D.assert(
|
|
!isSelected.Any((bool val) => val == null),
|
|
() => "All elements of isSelected must be non-null.\n" +
|
|
"The current list of isSelected values is as follows:\n" +
|
|
$"{isSelected}"
|
|
);
|
|
D.assert(
|
|
focusNodes == null || !focusNodes.Any((FocusNode val) => val == null),
|
|
() => "All elements of focusNodes must be non-null.\n" +
|
|
"The current list of focus node values is as follows:\n" +
|
|
$"{focusNodes}"
|
|
);
|
|
D.assert(
|
|
() => {
|
|
if (focusNodes != null) {
|
|
return focusNodes.Count == children.Count;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
() => "focusNodes.length must match children.length.\n" +
|
|
$"There are {focusNodes.Count} focus nodes, while " +
|
|
$"there are {children.Count} children."
|
|
);
|
|
|
|
ThemeData theme = Theme.of(context);
|
|
ToggleButtonsThemeData toggleButtonsTheme = ToggleButtonsTheme.of(context);
|
|
TextDirection textDirection = Directionality.of(context);
|
|
|
|
var childrenList = new List<Widget>(children.Count);
|
|
for (var i = 0; i < children.Count; i++) {
|
|
var index = i;
|
|
BorderRadius edgeBorderRadius =
|
|
_getEdgeBorderRadius(index, children.Count, textDirection, toggleButtonsTheme);
|
|
BorderRadius clipBorderRadius =
|
|
_getClipBorderRadius(index, children.Count, textDirection, toggleButtonsTheme);
|
|
|
|
BorderSide leadingBorderSide = _getLeadingBorderSide(index, theme, toggleButtonsTheme);
|
|
BorderSide horizontalBorderSide = _getHorizontalBorderSide(index, theme, toggleButtonsTheme);
|
|
BorderSide trailingBorderSide = _getTrailingBorderSide(index, theme, toggleButtonsTheme);
|
|
|
|
childrenList.Add(new _ToggleButton(
|
|
selected: isSelected[index],
|
|
textStyle: textStyle,
|
|
constraints: constraints,
|
|
color: color,
|
|
selectedColor: selectedColor,
|
|
disabledColor: disabledColor,
|
|
fillColor: fillColor ?? toggleButtonsTheme.fillColor,
|
|
focusColor: focusColor ?? toggleButtonsTheme.focusColor,
|
|
highlightColor: highlightColor ?? toggleButtonsTheme.highlightColor,
|
|
hoverColor: hoverColor ?? toggleButtonsTheme.hoverColor,
|
|
splashColor: splashColor ?? toggleButtonsTheme.splashColor,
|
|
focusNode: focusNodes != null ? focusNodes[index] : null,
|
|
onPressed: onPressed != null
|
|
? () => { onPressed(index); }
|
|
: (VoidCallback) null,
|
|
leadingBorderSide: leadingBorderSide,
|
|
horizontalBorderSide: horizontalBorderSide,
|
|
trailingBorderSide: trailingBorderSide,
|
|
borderRadius: edgeBorderRadius,
|
|
clipRadius: clipBorderRadius,
|
|
isFirstButton: index == 0,
|
|
isLastButton: index == children.Count - 1,
|
|
child: children[index]
|
|
));
|
|
}
|
|
|
|
return new IntrinsicHeight(
|
|
child: new Row(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: childrenList)
|
|
);
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new FlagProperty("disabled",
|
|
value: onPressed == null,
|
|
ifTrue: "Buttons are disabled",
|
|
ifFalse: "Buttons are enabled"
|
|
));
|
|
textStyle?.debugFillProperties(properties, prefix: "textStyle.");
|
|
properties.add(new ColorProperty("color", color, defaultValue: null));
|
|
properties.add(new ColorProperty("selectedColor", selectedColor, defaultValue: null));
|
|
properties.add(new ColorProperty("disabledColor", disabledColor, defaultValue: null));
|
|
properties.add(new ColorProperty("fillColor", fillColor, defaultValue: null));
|
|
properties.add(new ColorProperty("focusColor", focusColor, defaultValue: null));
|
|
properties.add(new ColorProperty("highlightColor", highlightColor, defaultValue: null));
|
|
properties.add(new ColorProperty("hoverColor", hoverColor, defaultValue: null));
|
|
properties.add(new ColorProperty("splashColor", splashColor, defaultValue: null));
|
|
properties.add(new ColorProperty("borderColor", borderColor, defaultValue: null));
|
|
properties.add(new ColorProperty("selectedBorderColor", selectedBorderColor, defaultValue: null));
|
|
properties.add(new ColorProperty("disabledBorderColor", disabledBorderColor, defaultValue: null));
|
|
properties.add(new DiagnosticsProperty<BorderRadius>("borderRadius", borderRadius, defaultValue: null));
|
|
properties.add(new FloatProperty("borderWidth", borderWidth, defaultValue: null));
|
|
}
|
|
}
|
|
|
|
|
|
class _ToggleButton : StatelessWidget {
|
|
public _ToggleButton(
|
|
Key key = null,
|
|
bool selected = false,
|
|
TextStyle textStyle = null,
|
|
BoxConstraints constraints = null,
|
|
Color color = null,
|
|
Color selectedColor = null,
|
|
Color disabledColor = null,
|
|
Color fillColor = null,
|
|
Color focusColor = null,
|
|
Color highlightColor = null,
|
|
Color hoverColor = null,
|
|
Color splashColor = null,
|
|
FocusNode focusNode = null,
|
|
VoidCallback onPressed = null,
|
|
BorderSide leadingBorderSide = null,
|
|
BorderSide horizontalBorderSide = null,
|
|
BorderSide trailingBorderSide = null,
|
|
BorderRadius borderRadius = null,
|
|
BorderRadius clipRadius = null,
|
|
bool? isFirstButton = null,
|
|
bool? isLastButton = null,
|
|
Widget child = null
|
|
) : base(key: key) {
|
|
D.assert(isFirstButton != null);
|
|
D.assert(isLastButton != null);
|
|
|
|
this.selected = selected;
|
|
this.textStyle = textStyle;
|
|
this.constraints = constraints;
|
|
this.color = color;
|
|
this.selectedColor = selectedColor;
|
|
this.disabledColor = disabledColor;
|
|
this.fillColor = fillColor;
|
|
this.focusColor = focusColor;
|
|
this.highlightColor = highlightColor;
|
|
this.hoverColor = hoverColor;
|
|
this.splashColor = splashColor;
|
|
this.focusNode = focusNode;
|
|
this.onPressed = onPressed;
|
|
this.leadingBorderSide = leadingBorderSide;
|
|
this.horizontalBorderSide = horizontalBorderSide;
|
|
this.trailingBorderSide = trailingBorderSide;
|
|
this.borderRadius = borderRadius;
|
|
this.clipRadius = clipRadius;
|
|
this.isFirstButton = isFirstButton.Value;
|
|
this.isLastButton = isLastButton.Value;
|
|
this.child = child;
|
|
}
|
|
|
|
public readonly bool selected;
|
|
|
|
public readonly TextStyle textStyle;
|
|
|
|
public readonly BoxConstraints constraints;
|
|
|
|
public readonly Color color;
|
|
|
|
public readonly Color selectedColor;
|
|
|
|
public readonly Color disabledColor;
|
|
|
|
public readonly Color fillColor;
|
|
|
|
public readonly Color focusColor;
|
|
|
|
public readonly Color hoverColor;
|
|
|
|
public readonly Color highlightColor;
|
|
|
|
public readonly Color splashColor;
|
|
|
|
public readonly FocusNode focusNode;
|
|
|
|
public readonly VoidCallback onPressed;
|
|
|
|
public readonly BorderSide leadingBorderSide;
|
|
|
|
public readonly BorderSide horizontalBorderSide;
|
|
|
|
public readonly BorderSide trailingBorderSide;
|
|
|
|
public readonly BorderRadius borderRadius;
|
|
|
|
public readonly BorderRadius clipRadius;
|
|
|
|
public readonly bool isFirstButton;
|
|
|
|
public readonly bool isLastButton;
|
|
|
|
public readonly Widget child;
|
|
|
|
public override Widget build(BuildContext context) {
|
|
D.assert(material_.debugCheckHasMaterial(context));
|
|
Color currentColor = null;
|
|
Color currentFillColor = null;
|
|
Color currentFocusColor = null;
|
|
Color currentHoverColor = null;
|
|
Color currentSplashColor = null;
|
|
ThemeData theme = Theme.of(context);
|
|
ToggleButtonsThemeData toggleButtonsTheme = ToggleButtonsTheme.of(context);
|
|
|
|
if (onPressed != null && selected) {
|
|
currentColor = selectedColor
|
|
?? toggleButtonsTheme.selectedColor
|
|
?? theme.colorScheme.primary;
|
|
currentFillColor = fillColor
|
|
?? theme.colorScheme.primary.withOpacity(0.12f);
|
|
currentFocusColor = focusColor
|
|
?? toggleButtonsTheme.focusColor
|
|
?? theme.colorScheme.primary.withOpacity(0.12f);
|
|
currentHoverColor = hoverColor
|
|
?? toggleButtonsTheme.hoverColor
|
|
?? theme.colorScheme.primary.withOpacity(0.04f);
|
|
currentSplashColor = splashColor
|
|
?? toggleButtonsTheme.splashColor
|
|
?? theme.colorScheme.primary.withOpacity(0.16f);
|
|
}
|
|
else if (onPressed != null && !selected) {
|
|
currentColor = color
|
|
?? toggleButtonsTheme.color
|
|
?? theme.colorScheme.onSurface.withOpacity(0.87f);
|
|
currentFillColor = theme.colorScheme.surface.withOpacity(0.0f);
|
|
currentFocusColor = focusColor
|
|
?? toggleButtonsTheme.focusColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.12f);
|
|
currentHoverColor = hoverColor
|
|
?? toggleButtonsTheme.hoverColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.04f);
|
|
currentSplashColor = splashColor
|
|
?? toggleButtonsTheme.splashColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.16f);
|
|
}
|
|
else {
|
|
currentColor = disabledColor
|
|
?? toggleButtonsTheme.disabledColor
|
|
?? theme.colorScheme.onSurface.withOpacity(0.38f);
|
|
currentFillColor = theme.colorScheme.surface.withOpacity(0.0f);
|
|
}
|
|
|
|
TextStyle currentTextStyle = textStyle ?? toggleButtonsTheme.textStyle ?? theme.textTheme.bodyText2;
|
|
BoxConstraints currentConstraints = constraints ?? toggleButtonsTheme.constraints ??
|
|
new BoxConstraints(minWidth: material_.kMinInteractiveDimension,
|
|
minHeight: material_.kMinInteractiveDimension);
|
|
|
|
Widget result = new ClipRRect(
|
|
borderRadius: clipRadius,
|
|
child: new RawMaterialButton(
|
|
textStyle: currentTextStyle.copyWith(
|
|
color: currentColor
|
|
),
|
|
constraints: currentConstraints,
|
|
elevation: 0.0f,
|
|
highlightElevation: 0.0f,
|
|
fillColor: currentFillColor,
|
|
focusColor: currentFocusColor,
|
|
highlightColor: highlightColor
|
|
?? theme.colorScheme.surface.withOpacity(0.0f),
|
|
hoverColor: currentHoverColor,
|
|
splashColor: currentSplashColor,
|
|
focusNode: focusNode,
|
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
onPressed: onPressed,
|
|
child: child
|
|
)
|
|
);
|
|
|
|
return new _SelectToggleButton(
|
|
key: key,
|
|
leadingBorderSide: leadingBorderSide,
|
|
horizontalBorderSide: horizontalBorderSide,
|
|
trailingBorderSide: trailingBorderSide,
|
|
borderRadius: borderRadius,
|
|
isFirstButton: isFirstButton,
|
|
isLastButton: isLastButton,
|
|
child: result
|
|
);
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new FlagProperty("selected",
|
|
value: selected,
|
|
ifTrue: "Button is selected",
|
|
ifFalse: "Button is unselected"
|
|
));
|
|
}
|
|
}
|
|
|
|
|
|
class _SelectToggleButton : SingleChildRenderObjectWidget {
|
|
public _SelectToggleButton(
|
|
Key key = null,
|
|
Widget child = null,
|
|
BorderSide leadingBorderSide = null,
|
|
BorderSide horizontalBorderSide = null,
|
|
BorderSide trailingBorderSide = null,
|
|
BorderRadius borderRadius = null,
|
|
bool? isFirstButton = null,
|
|
bool? isLastButton = null
|
|
) : base(key: key, child: child) {
|
|
D.assert(isFirstButton != null);
|
|
D.assert(isLastButton != null);
|
|
|
|
this.leadingBorderSide = leadingBorderSide;
|
|
this.horizontalBorderSide = horizontalBorderSide;
|
|
this.trailingBorderSide = trailingBorderSide;
|
|
this.borderRadius = borderRadius;
|
|
this.isFirstButton = isFirstButton.Value;
|
|
this.isLastButton = isLastButton.Value;
|
|
}
|
|
|
|
public readonly BorderSide leadingBorderSide;
|
|
|
|
public readonly BorderSide horizontalBorderSide;
|
|
|
|
public readonly BorderSide trailingBorderSide;
|
|
|
|
public readonly BorderRadius borderRadius;
|
|
|
|
public readonly bool isFirstButton;
|
|
|
|
public readonly bool isLastButton;
|
|
|
|
public override RenderObject createRenderObject(BuildContext context) {
|
|
return new _SelectToggleButtonRenderObject(
|
|
leadingBorderSide,
|
|
horizontalBorderSide,
|
|
trailingBorderSide,
|
|
borderRadius,
|
|
isFirstButton,
|
|
isLastButton,
|
|
Directionality.of(context)
|
|
);
|
|
}
|
|
|
|
public override void updateRenderObject(BuildContext context, RenderObject renderObject) {
|
|
var _renderObject = (_SelectToggleButtonRenderObject) renderObject;
|
|
_renderObject.leadingBorderSide = leadingBorderSide;
|
|
_renderObject.horizontalBorderSide = horizontalBorderSide;
|
|
_renderObject.trailingBorderSide = trailingBorderSide;
|
|
_renderObject.borderRadius = borderRadius;
|
|
_renderObject.isFirstButton = isFirstButton;
|
|
_renderObject.isLastButton = isLastButton;
|
|
_renderObject.textDirection = Directionality.of(context);
|
|
}
|
|
}
|
|
|
|
class _SelectToggleButtonRenderObject : RenderShiftedBox {
|
|
public _SelectToggleButtonRenderObject(
|
|
BorderSide leadingBorderSide,
|
|
BorderSide horizontalBorderSide,
|
|
BorderSide trailingBorderSide,
|
|
BorderRadius borderRadius,
|
|
bool isFirstButton,
|
|
bool isLastButton,
|
|
TextDirection textDirection,
|
|
RenderBox child = null
|
|
) : base(child: child) {
|
|
_leadingBorderSide = leadingBorderSide;
|
|
_horizontalBorderSide = horizontalBorderSide;
|
|
_trailingBorderSide = trailingBorderSide;
|
|
_borderRadius = borderRadius;
|
|
_isFirstButton = isFirstButton;
|
|
_isLastButton = isLastButton;
|
|
_textDirection = textDirection;
|
|
}
|
|
|
|
public BorderSide leadingBorderSide {
|
|
get { return _leadingBorderSide; }
|
|
set {
|
|
if (_leadingBorderSide == value) {
|
|
return;
|
|
}
|
|
|
|
_leadingBorderSide = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
BorderSide _leadingBorderSide;
|
|
|
|
public BorderSide horizontalBorderSide {
|
|
get { return _horizontalBorderSide; }
|
|
set {
|
|
if (_horizontalBorderSide == value) {
|
|
return;
|
|
}
|
|
|
|
_horizontalBorderSide = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
BorderSide _horizontalBorderSide;
|
|
|
|
public BorderSide trailingBorderSide {
|
|
get { return _trailingBorderSide; }
|
|
set {
|
|
if (_trailingBorderSide == value) {
|
|
return;
|
|
}
|
|
|
|
_trailingBorderSide = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
BorderSide _trailingBorderSide;
|
|
|
|
public BorderRadius borderRadius {
|
|
get { return _borderRadius; }
|
|
set {
|
|
if (_borderRadius == value) {
|
|
return;
|
|
}
|
|
|
|
_borderRadius = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
BorderRadius _borderRadius;
|
|
|
|
public bool isFirstButton {
|
|
get { return _isFirstButton; }
|
|
set {
|
|
if (_isFirstButton == value) {
|
|
return;
|
|
}
|
|
|
|
_isFirstButton = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
bool _isFirstButton;
|
|
|
|
public bool isLastButton {
|
|
get { return _isLastButton; }
|
|
set {
|
|
if (_isLastButton == value) {
|
|
return;
|
|
}
|
|
|
|
_isLastButton = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
bool _isLastButton;
|
|
|
|
public TextDirection textDirection {
|
|
get { return _textDirection; }
|
|
set {
|
|
if (_textDirection == value) {
|
|
return;
|
|
}
|
|
|
|
_textDirection = value;
|
|
markNeedsLayout();
|
|
}
|
|
}
|
|
|
|
TextDirection _textDirection;
|
|
|
|
static float _maxHeight(RenderBox box, float width) {
|
|
return box == null ? 0.0f : box.getMaxIntrinsicHeight(width);
|
|
}
|
|
|
|
static float _minWidth(RenderBox box, float height) {
|
|
return box == null ? 0.0f : box.getMinIntrinsicWidth(height);
|
|
}
|
|
|
|
static float _maxWidth(RenderBox box, float height) {
|
|
return box == null ? 0.0f : box.getMaxIntrinsicWidth(height);
|
|
}
|
|
|
|
float computeDistanceToActualBaseline(TextBaseline baseline) {
|
|
return child.computeDistanceToActualBaseline(baseline).Value +
|
|
horizontalBorderSide.width;
|
|
}
|
|
|
|
protected internal override float computeMaxIntrinsicHeight(float width) {
|
|
return horizontalBorderSide.width +
|
|
_maxHeight(child, width) +
|
|
horizontalBorderSide.width;
|
|
}
|
|
|
|
protected internal override float computeMinIntrinsicHeight(float width) {
|
|
return computeMaxIntrinsicHeight(width);
|
|
}
|
|
|
|
protected internal override float computeMaxIntrinsicWidth(float height) {
|
|
float trailingWidth = trailingBorderSide == null ? 0.0f : trailingBorderSide.width;
|
|
return leadingBorderSide.width +
|
|
_maxWidth(child, height) +
|
|
trailingWidth;
|
|
}
|
|
|
|
protected internal override float computeMinIntrinsicWidth(float height) {
|
|
float trailingWidth = trailingBorderSide == null ? 0.0f : trailingBorderSide.width;
|
|
return leadingBorderSide.width +
|
|
_minWidth(child, height) +
|
|
trailingWidth;
|
|
}
|
|
|
|
protected override void performLayout() {
|
|
if (child == null) {
|
|
size = constraints.constrain(new Size(
|
|
leadingBorderSide.width + trailingBorderSide.width,
|
|
horizontalBorderSide.width * 2.0f
|
|
));
|
|
return;
|
|
}
|
|
|
|
float trailingBorderOffset = isLastButton ? trailingBorderSide.width : 0.0f;
|
|
float leftConstraint;
|
|
float rightConstraint;
|
|
|
|
BoxConstraints innerConstraints;
|
|
BoxParentData childParentData;
|
|
|
|
switch (textDirection) {
|
|
case TextDirection.ltr: {
|
|
rightConstraint = trailingBorderOffset;
|
|
leftConstraint = leadingBorderSide.width;
|
|
|
|
innerConstraints = constraints.deflate(
|
|
EdgeInsets.only(
|
|
left: leftConstraint,
|
|
top: horizontalBorderSide.width,
|
|
right: rightConstraint,
|
|
bottom: horizontalBorderSide.width
|
|
)
|
|
);
|
|
|
|
child.layout(innerConstraints, parentUsesSize: true);
|
|
|
|
childParentData = child.parentData as BoxParentData;
|
|
childParentData.offset = new Offset(leadingBorderSide.width, leadingBorderSide.width);
|
|
|
|
size = constraints.constrain(new Size(
|
|
leftConstraint + child.size.width + rightConstraint,
|
|
horizontalBorderSide.width * 2.0f + child.size.height
|
|
));
|
|
break;
|
|
}
|
|
|
|
case TextDirection.rtl: {
|
|
rightConstraint = leadingBorderSide.width;
|
|
leftConstraint = trailingBorderOffset;
|
|
|
|
innerConstraints = constraints.deflate(
|
|
EdgeInsets.only(
|
|
left: leftConstraint,
|
|
top: horizontalBorderSide.width,
|
|
right: rightConstraint,
|
|
bottom: horizontalBorderSide.width
|
|
)
|
|
);
|
|
|
|
child.layout(innerConstraints, parentUsesSize: true);
|
|
childParentData = child.parentData as BoxParentData;
|
|
|
|
if (isLastButton) {
|
|
childParentData.offset = new Offset(trailingBorderOffset, trailingBorderOffset);
|
|
}
|
|
else {
|
|
childParentData.offset = new Offset(0, horizontalBorderSide.width);
|
|
}
|
|
|
|
size = constraints.constrain(new Size(
|
|
leftConstraint + child.size.width + rightConstraint,
|
|
horizontalBorderSide.width * 2.0f + child.size.height
|
|
));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void paint(PaintingContext context, Offset offset) {
|
|
base.paint(context, offset);
|
|
Offset bottomRight = size.bottomRight(offset);
|
|
Rect outer = Rect.fromLTRB(offset.dx, offset.dy, bottomRight.dx, bottomRight.dy);
|
|
Rect center = outer.deflate(horizontalBorderSide.width / 2.0f);
|
|
const float sweepAngle = Mathf.PI / 2.0f;
|
|
|
|
RRect rrect = RRect.fromRectAndCorners(
|
|
center,
|
|
topLeft: borderRadius.topLeft,
|
|
topRight: borderRadius.topRight,
|
|
bottomLeft: borderRadius.bottomLeft,
|
|
bottomRight: borderRadius.bottomRight
|
|
).scaleRadii();
|
|
|
|
Rect tlCorner = Rect.fromLTWH(
|
|
rrect.left,
|
|
rrect.top,
|
|
rrect.tlRadiusX * 2.0f,
|
|
rrect.tlRadiusY * 2.0f
|
|
);
|
|
Rect blCorner = Rect.fromLTWH(
|
|
rrect.left,
|
|
rrect.bottom - (rrect.blRadiusY * 2.0f),
|
|
rrect.blRadiusX * 2.0f,
|
|
rrect.blRadiusY * 2.0f
|
|
);
|
|
Rect trCorner = Rect.fromLTWH(
|
|
rrect.right - (rrect.trRadiusX * 2.0f),
|
|
rrect.top,
|
|
rrect.trRadiusX * 2.0f,
|
|
rrect.trRadiusY * 2.0f
|
|
);
|
|
Rect brCorner = Rect.fromLTWH(
|
|
rrect.right - (rrect.brRadiusX * 2.0f),
|
|
rrect.bottom - (rrect.brRadiusY * 2.0f),
|
|
rrect.brRadiusX * 2.0f,
|
|
rrect.brRadiusY * 2.0f
|
|
);
|
|
|
|
Paint leadingPaint = leadingBorderSide.toPaint();
|
|
switch (textDirection) {
|
|
case TextDirection.ltr: {
|
|
if (isLastButton) {
|
|
Path leftPath = new Path();
|
|
leftPath.moveTo(rrect.left, rrect.bottom + leadingBorderSide.width / 2);
|
|
leftPath.lineTo(rrect.left, rrect.top - leadingBorderSide.width / 2);
|
|
context.canvas.drawPath(leftPath, leadingPaint);
|
|
|
|
Paint endingPaint = trailingBorderSide.toPaint();
|
|
Path endingPath = new Path();
|
|
endingPath.moveTo(rrect.left + horizontalBorderSide.width / 2.0f, rrect.top);
|
|
endingPath.lineTo(rrect.right - rrect.trRadiusX, rrect.top);
|
|
endingPath.addArc(trCorner, Mathf.PI * 3.0f / 2.0f, sweepAngle);
|
|
endingPath.lineTo(rrect.right, rrect.bottom - rrect.brRadiusY);
|
|
endingPath.addArc(brCorner, 0, sweepAngle);
|
|
endingPath.lineTo(rrect.left + horizontalBorderSide.width / 2.0f, rrect.bottom);
|
|
context.canvas.drawPath(endingPath, endingPaint);
|
|
}
|
|
else if (isFirstButton) {
|
|
Path leadingPath = new Path();
|
|
leadingPath.moveTo(outer.right, rrect.bottom);
|
|
leadingPath.lineTo(rrect.left + rrect.blRadiusX, rrect.bottom);
|
|
leadingPath.addArc(blCorner, Mathf.PI / 2.0f, sweepAngle);
|
|
leadingPath.lineTo(rrect.left, rrect.top + rrect.tlRadiusY);
|
|
leadingPath.addArc(tlCorner, Mathf.PI, sweepAngle);
|
|
leadingPath.lineTo(outer.right, rrect.top);
|
|
context.canvas.drawPath(leadingPath, leadingPaint);
|
|
}
|
|
else {
|
|
Path leadingPath = new Path();
|
|
leadingPath.moveTo(rrect.left, rrect.bottom + leadingBorderSide.width / 2);
|
|
leadingPath.lineTo(rrect.left, rrect.top - leadingBorderSide.width / 2);
|
|
context.canvas.drawPath(leadingPath, leadingPaint);
|
|
|
|
Paint horizontalPaint = horizontalBorderSide.toPaint();
|
|
Path horizontalPaths = new Path();
|
|
horizontalPaths.moveTo(rrect.left + horizontalBorderSide.width / 2.0f, rrect.top);
|
|
horizontalPaths.lineTo(outer.right - rrect.trRadiusX, rrect.top);
|
|
horizontalPaths.moveTo(rrect.left + horizontalBorderSide.width / 2.0f + rrect.tlRadiusX,
|
|
rrect.bottom);
|
|
horizontalPaths.lineTo(outer.right - rrect.trRadiusX, rrect.bottom);
|
|
context.canvas.drawPath(horizontalPaths, horizontalPaint);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TextDirection.rtl: {
|
|
if (isLastButton) {
|
|
Path leadingPath = new Path();
|
|
leadingPath.moveTo(rrect.right, rrect.bottom + leadingBorderSide.width / 2);
|
|
leadingPath.lineTo(rrect.right, rrect.top - leadingBorderSide.width / 2);
|
|
context.canvas.drawPath(leadingPath, leadingPaint);
|
|
|
|
Paint endingPaint = trailingBorderSide.toPaint();
|
|
Path endingPath = new Path();
|
|
endingPath.moveTo(rrect.right - horizontalBorderSide.width / 2.0f, rrect.top);
|
|
endingPath.lineTo(rrect.left + rrect.tlRadiusX, rrect.top);
|
|
endingPath.addArc(tlCorner, Mathf.PI * 3.0f / 2.0f, -sweepAngle);
|
|
endingPath.lineTo(rrect.left, rrect.bottom - rrect.blRadiusY);
|
|
endingPath.addArc(blCorner, Mathf.PI, -sweepAngle);
|
|
endingPath.lineTo(rrect.right - horizontalBorderSide.width / 2.0f, rrect.bottom);
|
|
context.canvas.drawPath(endingPath, endingPaint);
|
|
}
|
|
else if (isFirstButton) {
|
|
Path leadingPath = new Path();
|
|
leadingPath.moveTo(outer.left, rrect.bottom);
|
|
leadingPath.lineTo(rrect.right - rrect.brRadiusX, rrect.bottom);
|
|
leadingPath.addArc(brCorner, Mathf.PI / 2.0f, -sweepAngle);
|
|
leadingPath.lineTo(rrect.right, rrect.top + rrect.trRadiusY);
|
|
leadingPath.addArc(trCorner, 0, -sweepAngle);
|
|
leadingPath.lineTo(outer.left, rrect.top);
|
|
context.canvas.drawPath(leadingPath, leadingPaint);
|
|
}
|
|
else {
|
|
Path leadingPath = new Path();
|
|
leadingPath.moveTo(rrect.right, rrect.bottom + leadingBorderSide.width / 2);
|
|
leadingPath.lineTo(rrect.right, rrect.top - leadingBorderSide.width / 2);
|
|
context.canvas.drawPath(leadingPath, leadingPaint);
|
|
|
|
Paint horizontalPaint = horizontalBorderSide.toPaint();
|
|
Path horizontalPaths = new Path();
|
|
horizontalPaths.moveTo(rrect.right - horizontalBorderSide.width / 2.0f, rrect.top);
|
|
horizontalPaths.lineTo(outer.left - rrect.tlRadiusX, rrect.top);
|
|
horizontalPaths.moveTo(rrect.right - horizontalBorderSide.width / 2.0f + rrect.trRadiusX,
|
|
rrect.bottom);
|
|
horizontalPaths.lineTo(outer.left - rrect.tlRadiusX, rrect.bottom);
|
|
context.canvas.drawPath(horizontalPaths, horizontalPaint);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|