您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
560 行
21 KiB
560 行
21 KiB
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.gestures;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.scheduler;
|
|
using Unity.UIWidgets.service;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
using ImageUtils = Unity.UIWidgets.widgets.ImageUtils;
|
|
|
|
namespace Unity.UIWidgets.material {
|
|
enum _SwitchType {
|
|
material,
|
|
adaptive
|
|
}
|
|
|
|
public class Switch : StatefulWidget {
|
|
internal const float _kTrackHeight = 14.0f;
|
|
internal const float _kTrackWidth = 33.0f;
|
|
internal const float _kTrackRadius = _kTrackHeight / 2.0f;
|
|
internal const float _kThumbRadius = 10.0f;
|
|
internal const float _kSwitchWidth = _kTrackWidth - 2 * _kTrackRadius + 2 * Constants.kRadialReactionRadius;
|
|
internal const float _kSwitchHeight = 2 * Constants.kRadialReactionRadius + 8.0f;
|
|
internal const float _kSwitchHeightCollapsed = 2 * Constants.kRadialReactionRadius;
|
|
|
|
public Switch(
|
|
Key key = null,
|
|
bool? value = null,
|
|
ValueChanged<bool?> onChanged = null,
|
|
Color activeColor = null,
|
|
Color activeTrackColor = null,
|
|
Color inactiveThumbColor = null,
|
|
Color inactiveTrackColor = null,
|
|
ImageProvider activeThumbImage = null,
|
|
ImageProvider inactiveThumbImage = null,
|
|
MaterialTapTargetSize? materialTapTargetSize = null,
|
|
DragStartBehavior dragStartBehavior = DragStartBehavior.start
|
|
) : this(
|
|
key: key,
|
|
value: value,
|
|
onChanged: onChanged,
|
|
activeColor: activeColor,
|
|
activeTrackColor: activeTrackColor,
|
|
inactiveThumbColor: inactiveThumbColor,
|
|
inactiveTrackColor: inactiveTrackColor,
|
|
activeThumbImage: activeThumbImage,
|
|
inactiveThumbImage: inactiveThumbImage,
|
|
materialTapTargetSize: materialTapTargetSize,
|
|
switchType: _SwitchType.material,
|
|
dragStartBehavior: dragStartBehavior
|
|
) {
|
|
}
|
|
|
|
Switch(
|
|
Key key = null,
|
|
bool? value = null,
|
|
ValueChanged<bool?> onChanged = null,
|
|
Color activeColor = null,
|
|
Color activeTrackColor = null,
|
|
Color inactiveThumbColor = null,
|
|
Color inactiveTrackColor = null,
|
|
ImageProvider activeThumbImage = null,
|
|
ImageProvider inactiveThumbImage = null,
|
|
MaterialTapTargetSize? materialTapTargetSize = null,
|
|
_SwitchType switchType = _SwitchType.material,
|
|
DragStartBehavior dragStartBehavior = DragStartBehavior.start
|
|
) : base(key: key) {
|
|
D.assert(value != null);
|
|
this.value = value.Value;
|
|
D.assert(onChanged != null);
|
|
this.onChanged = onChanged;
|
|
this.activeColor = activeColor;
|
|
this.activeTrackColor = activeTrackColor;
|
|
this.inactiveThumbColor = inactiveThumbColor;
|
|
this.inactiveTrackColor = inactiveTrackColor;
|
|
this.activeThumbImage = activeThumbImage;
|
|
this.inactiveThumbImage = inactiveThumbImage;
|
|
this.materialTapTargetSize = materialTapTargetSize;
|
|
_switchType = switchType;
|
|
this.dragStartBehavior = dragStartBehavior;
|
|
}
|
|
|
|
public static Switch adaptive(
|
|
Key key = null,
|
|
bool? value = null,
|
|
ValueChanged<bool?> onChanged = null,
|
|
Color activeColor = null,
|
|
Color activeTrackColor = null,
|
|
Color inactiveThumbColor = null,
|
|
Color inactiveTrackColor = null,
|
|
ImageProvider activeThumbImage = null,
|
|
ImageProvider inactiveThumbImage = null,
|
|
MaterialTapTargetSize? materialTapTargetSize = null,
|
|
DragStartBehavior dragStartBehavior = DragStartBehavior.down
|
|
) {
|
|
return new Switch(key: key,
|
|
value: value,
|
|
onChanged: onChanged,
|
|
activeColor: activeColor,
|
|
activeTrackColor: activeTrackColor,
|
|
inactiveThumbColor: inactiveThumbColor,
|
|
inactiveTrackColor: inactiveTrackColor,
|
|
activeThumbImage: activeThumbImage,
|
|
inactiveThumbImage: inactiveThumbImage,
|
|
materialTapTargetSize: materialTapTargetSize,
|
|
switchType: _SwitchType.adaptive
|
|
);
|
|
}
|
|
|
|
public readonly bool value;
|
|
|
|
public readonly ValueChanged<bool?> onChanged;
|
|
|
|
public readonly Color activeColor;
|
|
|
|
public readonly Color activeTrackColor;
|
|
|
|
public readonly Color inactiveThumbColor;
|
|
|
|
public readonly Color inactiveTrackColor;
|
|
|
|
public readonly ImageProvider activeThumbImage;
|
|
|
|
public readonly ImageProvider inactiveThumbImage;
|
|
|
|
public readonly MaterialTapTargetSize? materialTapTargetSize;
|
|
|
|
internal readonly _SwitchType _switchType;
|
|
|
|
public readonly DragStartBehavior dragStartBehavior;
|
|
|
|
public override State createState() {
|
|
return new _SwitchState();
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new FlagProperty("value", value: value, ifTrue: "on", ifFalse: "off", showName: true));
|
|
properties.add(
|
|
new ObjectFlagProperty<ValueChanged<bool?>>("onChanged", onChanged, ifNull: "disabled"));
|
|
}
|
|
}
|
|
|
|
class _SwitchState : TickerProviderStateMixin<Switch> {
|
|
Size getSwitchSize(ThemeData theme) {
|
|
switch (widget.materialTapTargetSize ?? theme.materialTapTargetSize) {
|
|
case MaterialTapTargetSize.padded:
|
|
return new Size(Switch._kSwitchWidth, Switch._kSwitchHeight);
|
|
case MaterialTapTargetSize.shrinkWrap:
|
|
return new Size(Switch._kSwitchWidth, Switch._kSwitchHeightCollapsed);
|
|
}
|
|
|
|
D.assert(false);
|
|
return null;
|
|
}
|
|
|
|
Widget buildMaterialSwitch(BuildContext context) {
|
|
D.assert(MaterialD.debugCheckHasMaterial(context));
|
|
ThemeData theme = Theme.of(context);
|
|
bool isDark = theme.brightness == Brightness.dark;
|
|
|
|
Color activeThumbColor = widget.activeColor ?? theme.toggleableActiveColor;
|
|
Color activeTrackColor = widget.activeTrackColor ?? activeThumbColor.withAlpha(0x80);
|
|
|
|
Color inactiveThumbColor;
|
|
Color inactiveTrackColor;
|
|
if (widget.onChanged != null) {
|
|
Color black32 = new Color(0x52000000); // Black with 32% opacity
|
|
inactiveThumbColor = widget.inactiveThumbColor ??
|
|
(isDark ? Colors.grey.shade400 : Colors.grey.shade50);
|
|
inactiveTrackColor = widget.inactiveTrackColor ?? (isDark ? Colors.white30 : black32);
|
|
}
|
|
else {
|
|
inactiveThumbColor = widget.inactiveThumbColor ??
|
|
(isDark ? Colors.grey.shade800 : Colors.grey.shade400);
|
|
inactiveTrackColor = widget.inactiveTrackColor ?? (isDark ? Colors.white10 : Colors.black12);
|
|
}
|
|
|
|
return new _SwitchRenderObjectWidget(
|
|
dragStartBehavior: widget.dragStartBehavior,
|
|
value: widget.value,
|
|
activeColor: activeThumbColor,
|
|
inactiveColor: inactiveThumbColor,
|
|
activeThumbImage: widget.activeThumbImage,
|
|
inactiveThumbImage: widget.inactiveThumbImage,
|
|
activeTrackColor: activeTrackColor,
|
|
inactiveTrackColor: inactiveTrackColor,
|
|
configuration: ImageUtils.createLocalImageConfiguration(context),
|
|
onChanged: widget.onChanged,
|
|
additionalConstraints: BoxConstraints.tight(getSwitchSize(theme)),
|
|
vsync: this
|
|
);
|
|
}
|
|
|
|
// Widget buildCupertinoSwitch(BuildContext context) {
|
|
// Size size = this.getSwitchSize(Theme.of(context));
|
|
// return new Container(
|
|
// width: size.width, // Same size as the Material switch.
|
|
// height: size.height,
|
|
// alignment: Alignment.center,
|
|
// child: CupertinoSwitch(
|
|
// value: this.widget.value,
|
|
// onChanged: this.widget.onChanged,
|
|
// activeColor: this.widget.activeColor
|
|
// )
|
|
// );
|
|
// }
|
|
|
|
public override Widget build(BuildContext context) {
|
|
switch (widget._switchType) {
|
|
case _SwitchType.material:
|
|
return buildMaterialSwitch(context);
|
|
|
|
case _SwitchType.adaptive: {
|
|
return buildMaterialSwitch(context);
|
|
// ThemeData theme = Theme.of(context);
|
|
// D.assert(theme.platform != null);
|
|
// switch (theme.platform) {
|
|
// case TargetPlatform.android:
|
|
// return buildMaterialSwitch(context);
|
|
// case TargetPlatform.iOS:
|
|
// return buildCupertinoSwitch(context);
|
|
// }
|
|
// break;
|
|
}
|
|
}
|
|
|
|
D.assert(false);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class _SwitchRenderObjectWidget : LeafRenderObjectWidget {
|
|
public _SwitchRenderObjectWidget(
|
|
Key key = null,
|
|
bool? value = null,
|
|
Color activeColor = null,
|
|
Color inactiveColor = null,
|
|
ImageProvider activeThumbImage = null,
|
|
ImageProvider inactiveThumbImage = null,
|
|
Color activeTrackColor = null,
|
|
Color inactiveTrackColor = null,
|
|
ImageConfiguration configuration = null,
|
|
ValueChanged<bool?> onChanged = null,
|
|
TickerProvider vsync = null,
|
|
BoxConstraints additionalConstraints = null,
|
|
DragStartBehavior? dragStartBehavior = null
|
|
) : base(key: key) {
|
|
D.assert(value != null);
|
|
this.value = value.Value;
|
|
this.activeColor = activeColor;
|
|
this.inactiveColor = inactiveColor;
|
|
this.activeThumbImage = activeThumbImage;
|
|
this.inactiveThumbImage = inactiveThumbImage;
|
|
this.activeTrackColor = activeTrackColor;
|
|
this.inactiveTrackColor = inactiveTrackColor;
|
|
this.configuration = configuration;
|
|
this.onChanged = onChanged;
|
|
this.vsync = vsync;
|
|
this.additionalConstraints = additionalConstraints;
|
|
this.dragStartBehavior = dragStartBehavior;
|
|
}
|
|
|
|
public readonly bool value;
|
|
public readonly Color activeColor;
|
|
public readonly Color inactiveColor;
|
|
public readonly ImageProvider activeThumbImage;
|
|
public readonly ImageProvider inactiveThumbImage;
|
|
public readonly Color activeTrackColor;
|
|
public readonly Color inactiveTrackColor;
|
|
public readonly ImageConfiguration configuration;
|
|
public readonly ValueChanged<bool?> onChanged;
|
|
public readonly TickerProvider vsync;
|
|
public readonly BoxConstraints additionalConstraints;
|
|
public readonly DragStartBehavior? dragStartBehavior;
|
|
|
|
public override RenderObject createRenderObject(BuildContext context) {
|
|
return new _RenderSwitch(
|
|
dragStartBehavior: dragStartBehavior,
|
|
value: value,
|
|
activeColor: activeColor,
|
|
inactiveColor: inactiveColor,
|
|
activeThumbImage: activeThumbImage,
|
|
inactiveThumbImage: inactiveThumbImage,
|
|
activeTrackColor: activeTrackColor,
|
|
inactiveTrackColor: inactiveTrackColor,
|
|
configuration: configuration,
|
|
onChanged: onChanged,
|
|
additionalConstraints: additionalConstraints,
|
|
vsync: vsync
|
|
);
|
|
}
|
|
|
|
public override void updateRenderObject(BuildContext context, RenderObject renderObjectRaw) {
|
|
_RenderSwitch renderObject = (_RenderSwitch) renderObjectRaw;
|
|
|
|
renderObject.value = value;
|
|
renderObject.activeColor = activeColor;
|
|
renderObject.inactiveColor = inactiveColor;
|
|
renderObject.activeThumbImage = activeThumbImage;
|
|
renderObject.inactiveThumbImage = inactiveThumbImage;
|
|
renderObject.activeTrackColor = activeTrackColor;
|
|
renderObject.inactiveTrackColor = inactiveTrackColor;
|
|
renderObject.configuration = configuration;
|
|
renderObject.onChanged = onChanged;
|
|
renderObject.additionalConstraints = additionalConstraints;
|
|
renderObject.dragStartBehavior = dragStartBehavior;
|
|
renderObject.vsync = vsync;
|
|
}
|
|
}
|
|
|
|
class _RenderSwitch : RenderToggleable {
|
|
public _RenderSwitch(
|
|
bool? value = null,
|
|
Color activeColor = null,
|
|
Color inactiveColor = null,
|
|
ImageProvider activeThumbImage = null,
|
|
ImageProvider inactiveThumbImage = null,
|
|
Color activeTrackColor = null,
|
|
Color inactiveTrackColor = null,
|
|
ImageConfiguration configuration = null,
|
|
BoxConstraints additionalConstraints = null,
|
|
ValueChanged<bool?> onChanged = null,
|
|
TickerProvider vsync = null,
|
|
DragStartBehavior? dragStartBehavior = null
|
|
) : base(
|
|
value: value,
|
|
tristate: false,
|
|
activeColor: activeColor,
|
|
inactiveColor: inactiveColor,
|
|
onChanged: onChanged,
|
|
additionalConstraints: additionalConstraints,
|
|
vsync: vsync
|
|
) {
|
|
_activeThumbImage = activeThumbImage;
|
|
_inactiveThumbImage = inactiveThumbImage;
|
|
_activeTrackColor = activeTrackColor;
|
|
_inactiveTrackColor = inactiveTrackColor;
|
|
_configuration = configuration;
|
|
_drag = new HorizontalDragGestureRecognizer {
|
|
onStart = _handleDragStart,
|
|
onUpdate = _handleDragUpdate,
|
|
onEnd = _handleDragEnd,
|
|
dragStartBehavior = dragStartBehavior ?? DragStartBehavior.down
|
|
};
|
|
}
|
|
|
|
public ImageProvider activeThumbImage {
|
|
get { return _activeThumbImage; }
|
|
set {
|
|
if (value == _activeThumbImage) {
|
|
return;
|
|
}
|
|
|
|
_activeThumbImage = value;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
ImageProvider _activeThumbImage;
|
|
|
|
public ImageProvider inactiveThumbImage {
|
|
get { return _inactiveThumbImage; }
|
|
set {
|
|
if (value == _inactiveThumbImage) {
|
|
return;
|
|
}
|
|
|
|
_inactiveThumbImage = value;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
ImageProvider _inactiveThumbImage;
|
|
|
|
public Color activeTrackColor {
|
|
get { return _activeTrackColor; }
|
|
set {
|
|
D.assert(value != null);
|
|
if (value == _activeTrackColor) {
|
|
return;
|
|
}
|
|
|
|
_activeTrackColor = value;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
Color _activeTrackColor;
|
|
|
|
public Color inactiveTrackColor {
|
|
get { return _inactiveTrackColor; }
|
|
set {
|
|
D.assert(value != null);
|
|
if (value == _inactiveTrackColor) {
|
|
return;
|
|
}
|
|
|
|
_inactiveTrackColor = value;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
Color _inactiveTrackColor;
|
|
|
|
public ImageConfiguration configuration {
|
|
get { return _configuration; }
|
|
set {
|
|
D.assert(value != null);
|
|
if (value == _configuration) {
|
|
return;
|
|
}
|
|
|
|
_configuration = value;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
ImageConfiguration _configuration;
|
|
|
|
public DragStartBehavior? dragStartBehavior {
|
|
get { return _drag.dragStartBehavior; }
|
|
set { _drag.dragStartBehavior = value ?? DragStartBehavior.down; }
|
|
}
|
|
|
|
|
|
public override void detach() {
|
|
_cachedThumbPainter?.Dispose();
|
|
_cachedThumbPainter = null;
|
|
base.detach();
|
|
}
|
|
|
|
float _trackInnerLength {
|
|
get { return size.width - 2.0f * Constants.kRadialReactionRadius; }
|
|
}
|
|
|
|
HorizontalDragGestureRecognizer _drag;
|
|
|
|
void _handleDragStart(DragStartDetails details) {
|
|
if (isInteractive) {
|
|
reactionController.forward();
|
|
}
|
|
}
|
|
|
|
void _handleDragUpdate(DragUpdateDetails details) {
|
|
if (isInteractive) {
|
|
position.curve = null;
|
|
position.reverseCurve = null;
|
|
float delta = details.primaryDelta.Value / _trackInnerLength;
|
|
positionController.setValue(positionController.value + delta);
|
|
}
|
|
}
|
|
|
|
void _handleDragEnd(DragEndDetails details) {
|
|
if (position.value >= 0.5) {
|
|
positionController.forward();
|
|
}
|
|
else {
|
|
positionController.reverse();
|
|
}
|
|
|
|
reactionController.reverse();
|
|
}
|
|
|
|
public override void handleEvent(PointerEvent evt, HitTestEntry entry) {
|
|
D.assert(debugHandleEvent(evt, entry));
|
|
if (evt is PointerDownEvent && onChanged != null) {
|
|
_drag.addPointer((PointerDownEvent) evt);
|
|
}
|
|
|
|
base.handleEvent(evt, entry);
|
|
}
|
|
|
|
Color _cachedThumbColor;
|
|
ImageProvider _cachedThumbImage;
|
|
BoxPainter _cachedThumbPainter;
|
|
|
|
BoxDecoration _createDefaultThumbDecoration(Color color, ImageProvider image) {
|
|
return new BoxDecoration(
|
|
color: color,
|
|
image: image == null ? null : new DecorationImage(image: image),
|
|
shape: BoxShape.circle,
|
|
boxShadow: ShadowConstants.kElevationToShadow[1]
|
|
);
|
|
}
|
|
|
|
bool _isPainting = false;
|
|
|
|
void _handleDecorationChanged() {
|
|
if (!_isPainting) {
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
public override void paint(PaintingContext context, Offset offset) {
|
|
Canvas canvas = context.canvas;
|
|
|
|
bool isEnabled = onChanged != null;
|
|
float currentValue = position.value;
|
|
|
|
float visualPosition = currentValue;
|
|
|
|
Color trackColor = isEnabled
|
|
? Color.lerp(inactiveTrackColor, activeTrackColor, currentValue)
|
|
: inactiveTrackColor;
|
|
|
|
Color thumbColor = isEnabled
|
|
? Color.lerp(inactiveColor, activeColor, currentValue)
|
|
: inactiveColor;
|
|
|
|
ImageProvider thumbImage = isEnabled
|
|
? (currentValue < 0.5 ? inactiveThumbImage : activeThumbImage)
|
|
: inactiveThumbImage;
|
|
|
|
// Paint the track
|
|
Paint paint = new Paint {color = trackColor};
|
|
float trackHorizontalPadding = Constants.kRadialReactionRadius - Switch._kTrackRadius;
|
|
Rect trackRect = Rect.fromLTWH(
|
|
offset.dx + trackHorizontalPadding,
|
|
offset.dy + (size.height - Switch._kTrackHeight) / 2.0f,
|
|
size.width - 2.0f * trackHorizontalPadding,
|
|
Switch._kTrackHeight
|
|
);
|
|
RRect trackRRect = RRect.fromRectAndRadius(trackRect, Radius.circular(Switch._kTrackRadius));
|
|
canvas.drawRRect(trackRRect, paint);
|
|
|
|
Offset thumbPosition = new Offset(
|
|
Constants.kRadialReactionRadius + visualPosition * _trackInnerLength,
|
|
size.height / 2.0f
|
|
);
|
|
|
|
paintRadialReaction(canvas, offset, thumbPosition);
|
|
|
|
try {
|
|
_isPainting = true;
|
|
BoxPainter thumbPainter;
|
|
if (_cachedThumbPainter == null || thumbColor != _cachedThumbColor ||
|
|
thumbImage != _cachedThumbImage) {
|
|
_cachedThumbColor = thumbColor;
|
|
_cachedThumbImage = thumbImage;
|
|
_cachedThumbPainter = _createDefaultThumbDecoration(thumbColor, thumbImage)
|
|
.createBoxPainter(_handleDecorationChanged);
|
|
}
|
|
|
|
thumbPainter = _cachedThumbPainter;
|
|
|
|
float inset = 1.0f - (currentValue - 0.5f).abs() * 2.0f;
|
|
float radius = Switch._kThumbRadius - inset;
|
|
thumbPainter.paint(
|
|
canvas,
|
|
thumbPosition + offset - new Offset(radius, radius),
|
|
configuration.copyWith(size: Size.fromRadius(radius))
|
|
);
|
|
}
|
|
finally {
|
|
_isPainting = false;
|
|
}
|
|
}
|
|
}
|
|
}
|