@@ -127,6 +127,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
value: value,
|
||||
activeColor: activeColor,
|
||||
onChanged: onChanged,
|
||||
textDirection: Directionality.of(context),
|
||||
vsync: vsync,
|
||||
);
|
||||
}
|
||||
@@ -137,6 +138,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
..value = value
|
||||
..activeColor = activeColor
|
||||
..onChanged = onChanged
|
||||
..textDirection = Directionality.of(context)
|
||||
..vsync = vsync;
|
||||
}
|
||||
}
|
||||
@@ -159,6 +161,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
@required bool value,
|
||||
@required Color activeColor,
|
||||
ValueChanged<bool> onChanged,
|
||||
@required TextDirection textDirection,
|
||||
@required TickerProvider vsync,
|
||||
}) : assert(value != null),
|
||||
assert(activeColor != null),
|
||||
@@ -166,6 +169,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
_value = value,
|
||||
_activeColor = activeColor,
|
||||
_onChanged = onChanged,
|
||||
_textDirection = textDirection,
|
||||
_vsync = vsync,
|
||||
super(additionalConstraints: const BoxConstraints.tightFor(width: _kSwitchWidth, height: _kSwitchHeight)) {
|
||||
_tap = new TapGestureRecognizer()
|
||||
@@ -254,6 +258,16 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
}
|
||||
}
|
||||
|
||||
TextDirection get textDirection => _textDirection;
|
||||
TextDirection _textDirection;
|
||||
set textDirection(TextDirection value) {
|
||||
assert(value != null);
|
||||
if (_textDirection == value)
|
||||
return;
|
||||
_textDirection = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
bool get isInteractive => onChanged != null;
|
||||
|
||||
TapGestureRecognizer _tap;
|
||||
@@ -328,7 +342,15 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
_position
|
||||
..curve = null
|
||||
..reverseCurve = null;
|
||||
_positionController.value += details.primaryDelta / _kTrackInnerLength;
|
||||
final double delta = details.primaryDelta / _kTrackInnerLength;
|
||||
switch (textDirection) {
|
||||
case TextDirection.rtl:
|
||||
_positionController.value -= delta;
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
_positionController.value += delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,11 +400,21 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
final Canvas canvas = context.canvas;
|
||||
|
||||
final double currentPosition = _position.value;
|
||||
final double currentValue = _position.value;
|
||||
final double currentReactionValue = _reaction.value;
|
||||
|
||||
double visualPosition;
|
||||
switch (textDirection) {
|
||||
case TextDirection.rtl:
|
||||
visualPosition = 1.0 - currentValue;
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
visualPosition = currentValue;
|
||||
break;
|
||||
}
|
||||
|
||||
final Color trackColor = _value ? activeColor : _kTrackColor;
|
||||
final double borderThickness = 1.5 + (_kTrackRadius - 1.5) * math.max(currentReactionValue, currentPosition);
|
||||
final double borderThickness = 1.5 + (_kTrackRadius - 1.5) * math.max(currentReactionValue, currentValue);
|
||||
|
||||
final Paint paint = new Paint()
|
||||
..color = trackColor;
|
||||
@@ -401,12 +433,12 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox implements SemanticsAc
|
||||
final double thumbLeft = lerpDouble(
|
||||
trackRect.left + _kTrackInnerStart - CupertinoThumbPainter.radius,
|
||||
trackRect.left + _kTrackInnerEnd - CupertinoThumbPainter.radius - currentThumbExtension,
|
||||
currentPosition,
|
||||
visualPosition,
|
||||
);
|
||||
final double thumbRight = lerpDouble(
|
||||
trackRect.left + _kTrackInnerStart + CupertinoThumbPainter.radius + currentThumbExtension,
|
||||
trackRect.left + _kTrackInnerEnd + CupertinoThumbPainter.radius,
|
||||
currentPosition,
|
||||
visualPosition,
|
||||
);
|
||||
final double thumbCenterY = offset.dy + size.height / 2.0;
|
||||
|
||||
|
||||
@@ -168,18 +168,21 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
final TickerProvider vsync;
|
||||
|
||||
@override
|
||||
_RenderSwitch createRenderObject(BuildContext context) => new _RenderSwitch(
|
||||
value: value,
|
||||
activeColor: activeColor,
|
||||
inactiveColor: inactiveColor,
|
||||
activeThumbImage: activeThumbImage,
|
||||
inactiveThumbImage: inactiveThumbImage,
|
||||
activeTrackColor: activeTrackColor,
|
||||
inactiveTrackColor: inactiveTrackColor,
|
||||
configuration: configuration,
|
||||
onChanged: onChanged,
|
||||
vsync: vsync,
|
||||
);
|
||||
_RenderSwitch createRenderObject(BuildContext context) {
|
||||
return new _RenderSwitch(
|
||||
value: value,
|
||||
activeColor: activeColor,
|
||||
inactiveColor: inactiveColor,
|
||||
activeThumbImage: activeThumbImage,
|
||||
inactiveThumbImage: inactiveThumbImage,
|
||||
activeTrackColor: activeTrackColor,
|
||||
inactiveTrackColor: inactiveTrackColor,
|
||||
configuration: configuration,
|
||||
onChanged: onChanged,
|
||||
textDirection: Directionality.of(context),
|
||||
vsync: vsync,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, _RenderSwitch renderObject) {
|
||||
@@ -193,6 +196,7 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
..inactiveTrackColor = inactiveTrackColor
|
||||
..configuration = configuration
|
||||
..onChanged = onChanged
|
||||
..textDirection = Directionality.of(context)
|
||||
..vsync = vsync;
|
||||
}
|
||||
}
|
||||
@@ -214,13 +218,16 @@ class _RenderSwitch extends RenderToggleable {
|
||||
Color activeTrackColor,
|
||||
Color inactiveTrackColor,
|
||||
ImageConfiguration configuration,
|
||||
@required TextDirection textDirection,
|
||||
ValueChanged<bool> onChanged,
|
||||
@required TickerProvider vsync,
|
||||
}) : _activeThumbImage = activeThumbImage,
|
||||
}) : assert(textDirection != null),
|
||||
_activeThumbImage = activeThumbImage,
|
||||
_inactiveThumbImage = inactiveThumbImage,
|
||||
_activeTrackColor = activeTrackColor,
|
||||
_inactiveTrackColor = inactiveTrackColor,
|
||||
_configuration = configuration,
|
||||
_textDirection = textDirection,
|
||||
super(
|
||||
value: value,
|
||||
activeColor: activeColor,
|
||||
@@ -283,6 +290,16 @@ class _RenderSwitch extends RenderToggleable {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
TextDirection get textDirection => _textDirection;
|
||||
TextDirection _textDirection;
|
||||
set textDirection(TextDirection value) {
|
||||
assert(value != null);
|
||||
if (_textDirection == value)
|
||||
return;
|
||||
_textDirection = value;
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
@override
|
||||
void detach() {
|
||||
_cachedThumbPainter?.dispose();
|
||||
@@ -304,7 +321,15 @@ class _RenderSwitch extends RenderToggleable {
|
||||
position
|
||||
..curve = null
|
||||
..reverseCurve = null;
|
||||
positionController.value += details.primaryDelta / _trackInnerLength;
|
||||
final double delta = details.primaryDelta / _trackInnerLength;
|
||||
switch (textDirection) {
|
||||
case TextDirection.rtl:
|
||||
positionController.value -= delta;
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
positionController.value += delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,9 +378,19 @@ class _RenderSwitch extends RenderToggleable {
|
||||
final Canvas canvas = context.canvas;
|
||||
|
||||
final bool isActive = onChanged != null;
|
||||
final double currentPosition = position.value;
|
||||
final double currentValue = position.value;
|
||||
|
||||
final Color trackColor = isActive ? Color.lerp(inactiveTrackColor, activeTrackColor, currentPosition) : inactiveTrackColor;
|
||||
double visualPosition;
|
||||
switch (textDirection) {
|
||||
case TextDirection.rtl:
|
||||
visualPosition = 1.0 - currentValue;
|
||||
break;
|
||||
case TextDirection.ltr:
|
||||
visualPosition = currentValue;
|
||||
break;
|
||||
}
|
||||
|
||||
final Color trackColor = isActive ? Color.lerp(inactiveTrackColor, activeTrackColor, currentValue) : inactiveTrackColor;
|
||||
|
||||
// Paint the track
|
||||
final Paint paint = new Paint()
|
||||
@@ -371,7 +406,7 @@ class _RenderSwitch extends RenderToggleable {
|
||||
canvas.drawRRect(trackRRect, paint);
|
||||
|
||||
final Offset thumbPosition = new Offset(
|
||||
kRadialReactionRadius + currentPosition * _trackInnerLength,
|
||||
kRadialReactionRadius + visualPosition * _trackInnerLength,
|
||||
size.height / 2.0
|
||||
);
|
||||
|
||||
@@ -380,8 +415,8 @@ class _RenderSwitch extends RenderToggleable {
|
||||
try {
|
||||
_isPainting = true;
|
||||
BoxPainter thumbPainter;
|
||||
final Color thumbColor = isActive ? Color.lerp(inactiveColor, activeColor, currentPosition) : inactiveColor;
|
||||
final ImageProvider thumbImage = isActive ? (currentPosition < 0.5 ? inactiveThumbImage : activeThumbImage) : inactiveThumbImage;
|
||||
final Color thumbColor = isActive ? Color.lerp(inactiveColor, activeColor, currentValue) : inactiveColor;
|
||||
final ImageProvider thumbImage = isActive ? (currentValue < 0.5 ? inactiveThumbImage : activeThumbImage) : inactiveThumbImage;
|
||||
if (_cachedThumbPainter == null || thumbColor != _cachedThumbColor || thumbImage != _cachedThumbImage) {
|
||||
_cachedThumbColor = thumbColor;
|
||||
_cachedThumbImage = thumbImage;
|
||||
@@ -390,7 +425,7 @@ class _RenderSwitch extends RenderToggleable {
|
||||
thumbPainter = _cachedThumbPainter;
|
||||
|
||||
// The thumb contracts slightly during the animation
|
||||
final double inset = 1.0 - (currentPosition - 0.5).abs() * 2.0;
|
||||
final double inset = 1.0 - (currentValue - 0.5).abs() * 2.0;
|
||||
final double radius = _kThumbRadius - inset;
|
||||
thumbPainter.paint(
|
||||
canvas,
|
||||
|
||||
@@ -10,20 +10,23 @@ void main() {
|
||||
final Key switchKey = new UniqueKey();
|
||||
bool value = false;
|
||||
await tester.pumpWidget(
|
||||
new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Center(
|
||||
child: new CupertinoSwitch(
|
||||
key: switchKey,
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Center(
|
||||
child: new CupertinoSwitch(
|
||||
key: switchKey,
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -31,4 +34,93 @@ void main() {
|
||||
await tester.tap(find.byKey(switchKey));
|
||||
expect(value, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Switch can drag (LTR)', (WidgetTester tester) async {
|
||||
bool value = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Center(
|
||||
child: new CupertinoSwitch(
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Switch can drag (RTL)', (WidgetTester tester) async {
|
||||
bool value = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Center(
|
||||
child: new CupertinoSwitch(
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -12,23 +12,26 @@ void main() {
|
||||
bool value = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
child: new Switch(
|
||||
key: switchKey,
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
child: new Switch(
|
||||
key: switchKey,
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value, isFalse);
|
||||
@@ -36,26 +39,29 @@ void main() {
|
||||
expect(value, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Switch can drag', (WidgetTester tester) async {
|
||||
testWidgets('Switch can drag (LTR)', (WidgetTester tester) async {
|
||||
bool value = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
child: new Switch(
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
child: new Switch(
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value, isFalse);
|
||||
@@ -78,4 +84,50 @@ void main() {
|
||||
|
||||
expect(value, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Switch can drag (RTL)', (WidgetTester tester) async {
|
||||
bool value = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
child: new Switch(
|
||||
value: value,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(Switch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
|
||||
await tester.drag(find.byType(Switch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(Switch), const Offset(-30.0, 0.0));
|
||||
|
||||
expect(value, isTrue);
|
||||
|
||||
await tester.pump();
|
||||
await tester.drag(find.byType(Switch), const Offset(30.0, 0.0));
|
||||
|
||||
expect(value, isFalse);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user