Commit f0354b82 authored by Christian Mürtz's avatar Christian Mürtz Committed by Shi-Hao Hong

Add CheckboxListTile checkColor (#37636)

* Add checkColor to CheckboxListTile

* Create second paint for drawing check and dash

* Add activeColor test for Checkbox
Co-Authored-By: 's avatarShi-Hao Hong <shihaohong@google.com>
parent 50193212
...@@ -104,7 +104,7 @@ class Checkbox extends StatefulWidget { ...@@ -104,7 +104,7 @@ class Checkbox extends StatefulWidget {
/// Defaults to [ThemeData.toggleableActiveColor]. /// Defaults to [ThemeData.toggleableActiveColor].
final Color activeColor; final Color activeColor;
/// The color to use for the check icon when this checkbox is checked /// The color to use for the check icon when this checkbox is checked.
/// ///
/// Defaults to Color(0xFFFFFFFF) /// Defaults to Color(0xFFFFFFFF)
final Color checkColor; final Color checkColor;
...@@ -281,8 +281,8 @@ class _RenderCheckbox extends RenderToggleable { ...@@ -281,8 +281,8 @@ class _RenderCheckbox extends RenderToggleable {
} }
// White stroke used to paint the check and dash. // White stroke used to paint the check and dash.
void _initStrokePaint(Paint paint) { Paint _createStrokePaint() {
paint return Paint()
..color = checkColor ..color = checkColor
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..strokeWidth = _kStrokeWidth; ..strokeWidth = _kStrokeWidth;
...@@ -336,6 +336,7 @@ class _RenderCheckbox extends RenderToggleable { ...@@ -336,6 +336,7 @@ class _RenderCheckbox extends RenderToggleable {
final Canvas canvas = context.canvas; final Canvas canvas = context.canvas;
paintRadialReaction(canvas, offset, size.center(Offset.zero)); paintRadialReaction(canvas, offset, size.center(Offset.zero));
final Paint strokePaint = _createStrokePaint();
final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0); final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0);
final AnimationStatus status = position.status; final AnimationStatus status = position.status;
final double tNormalized = status == AnimationStatus.forward || status == AnimationStatus.completed final double tNormalized = status == AnimationStatus.forward || status == AnimationStatus.completed
...@@ -353,31 +354,29 @@ class _RenderCheckbox extends RenderToggleable { ...@@ -353,31 +354,29 @@ class _RenderCheckbox extends RenderToggleable {
} else { } else {
canvas.drawRRect(outer, paint); canvas.drawRRect(outer, paint);
_initStrokePaint(paint);
final double tShrink = (t - 0.5) * 2.0; final double tShrink = (t - 0.5) * 2.0;
if (_oldValue == null || value == null) if (_oldValue == null || value == null)
_drawDash(canvas, origin, tShrink, paint); _drawDash(canvas, origin, tShrink, strokePaint);
else else
_drawCheck(canvas, origin, tShrink, paint); _drawCheck(canvas, origin, tShrink, strokePaint);
} }
} else { // Two cases: null to true, true to null } else { // Two cases: null to true, true to null
final RRect outer = _outerRectAt(origin, 1.0); final RRect outer = _outerRectAt(origin, 1.0);
final Paint paint = Paint() ..color = _colorAt(1.0); final Paint paint = Paint() ..color = _colorAt(1.0);
canvas.drawRRect(outer, paint); canvas.drawRRect(outer, paint);
_initStrokePaint(paint);
if (tNormalized <= 0.5) { if (tNormalized <= 0.5) {
final double tShrink = 1.0 - tNormalized * 2.0; final double tShrink = 1.0 - tNormalized * 2.0;
if (_oldValue == true) if (_oldValue == true)
_drawCheck(canvas, origin, tShrink, paint); _drawCheck(canvas, origin, tShrink, strokePaint);
else else
_drawDash(canvas, origin, tShrink, paint); _drawDash(canvas, origin, tShrink, strokePaint);
} else { } else {
final double tExpand = (tNormalized - 0.5) * 2.0; final double tExpand = (tNormalized - 0.5) * 2.0;
if (value == true) if (value == true)
_drawCheck(canvas, origin, tExpand, paint); _drawCheck(canvas, origin, tExpand, strokePaint);
else else
_drawDash(canvas, origin, tExpand, paint); _drawDash(canvas, origin, tExpand, strokePaint);
} }
} }
} }
......
...@@ -17,7 +17,7 @@ import 'theme_data.dart'; ...@@ -17,7 +17,7 @@ import 'theme_data.dart';
/// The entire list tile is interactive: tapping anywhere in the tile toggles /// The entire list tile is interactive: tapping anywhere in the tile toggles
/// the checkbox. /// the checkbox.
/// ///
/// The [value], [onChanged], and [activeColor] properties of this widget are /// The [value], [onChanged], [activeColor] and [checkColor] properties of this widget are
/// identical to the similarly-named properties on the [Checkbox] widget. /// identical to the similarly-named properties on the [Checkbox] widget.
/// ///
/// The [title], [subtitle], [isThreeLine], and [dense] properties are like /// The [title], [subtitle], [isThreeLine], and [dense] properties are like
...@@ -268,6 +268,7 @@ class CheckboxListTile extends StatelessWidget { ...@@ -268,6 +268,7 @@ class CheckboxListTile extends StatelessWidget {
@required this.value, @required this.value,
@required this.onChanged, @required this.onChanged,
this.activeColor, this.activeColor,
this.checkColor,
this.title, this.title,
this.subtitle, this.subtitle,
this.isThreeLine = false, this.isThreeLine = false,
...@@ -317,6 +318,11 @@ class CheckboxListTile extends StatelessWidget { ...@@ -317,6 +318,11 @@ class CheckboxListTile extends StatelessWidget {
/// Defaults to accent color of the current [Theme]. /// Defaults to accent color of the current [Theme].
final Color activeColor; final Color activeColor;
/// The color to use for the check icon when this checkbox is checked.
///
/// Defaults to Color(0xFFFFFFFF).
final Color checkColor;
/// The primary content of the list tile. /// The primary content of the list tile.
/// ///
/// Typically a [Text] widget. /// Typically a [Text] widget.
...@@ -361,6 +367,7 @@ class CheckboxListTile extends StatelessWidget { ...@@ -361,6 +367,7 @@ class CheckboxListTile extends StatelessWidget {
value: value, value: value,
onChanged: onChanged, onChanged: onChanged,
activeColor: activeColor, activeColor: activeColor,
checkColor: checkColor,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
); );
Widget leading, trailing; Widget leading, trailing;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import '../rendering/mock_canvas.dart';
Widget wrap({ Widget child }) {
return MediaQuery(
data: const MediaQueryData(),
child: Directionality(
textDirection: TextDirection.ltr,
child: Material(child: child),
),
);
}
void main() {
testWidgets('CheckboxListTile control test', (WidgetTester tester) async {
final List<dynamic> log = <dynamic>[];
await tester.pumpWidget(wrap(
child: CheckboxListTile(
value: true,
onChanged: (bool value) { log.add(value); },
title: const Text('Hello'),
),
));
await tester.tap(find.text('Hello'));
log.add('-');
await tester.tap(find.byType(Checkbox));
expect(log, equals(<dynamic>[false, '-', false]));
});
testWidgets('CheckboxListTile checkColor test', (WidgetTester tester) async {
Widget buildFrame(Color color) {
return wrap(
child: CheckboxListTile(
value: true,
checkColor: color,
onChanged: (bool value) {},
),
);
}
RenderBox getCheckboxListTileRenderer() {
return tester.renderObject<RenderBox>(find.byType(CheckboxListTile));
}
await tester.pumpWidget(buildFrame(null));
await tester.pumpAndSettle();
expect(getCheckboxListTileRenderer(), paints..path(color: const Color(0xFFFFFFFF))); // paints's color is 0xFFFFFFFF (default color)
await tester.pumpWidget(buildFrame(const Color(0xFF000000)));
await tester.pumpAndSettle();
expect(getCheckboxListTileRenderer(), paints..path(color: const Color(0xFF000000))); // paints's color is 0xFF000000 (params)
});
testWidgets('CheckboxListTile activeColor test', (WidgetTester tester) async {
Widget buildFrame(Color themeColor, Color activeColor) {
return wrap(
child: Theme(
data: ThemeData(toggleableActiveColor: themeColor),
child: CheckboxListTile(
value: true,
activeColor: activeColor,
onChanged: (bool value) {},
),
),
);
}
RenderBox getCheckboxListTileRenderer() {
return tester.renderObject<RenderBox>(find.byType(CheckboxListTile));
}
await tester.pumpWidget(buildFrame(const Color(0xFF000000), null));
await tester.pumpAndSettle();
expect(getCheckboxListTileRenderer(), paints..rrect(color: const Color(0xFF000000))); // paints's color is 0xFF000000 (theme)
await tester.pumpWidget(buildFrame(const Color(0xFF000000), const Color(0xFFFFFFFF)));
await tester.pumpAndSettle();
expect(getCheckboxListTileRenderer(), paints..rrect(color: const Color(0xFFFFFFFF))); // paints's color is 0xFFFFFFFF (params)
});
}
...@@ -337,16 +337,20 @@ void main() { ...@@ -337,16 +337,20 @@ void main() {
}); });
testWidgets('CheckBox color rendering', (WidgetTester tester) async { testWidgets('CheckBox color rendering', (WidgetTester tester) async {
Widget buildFrame(Color color) { Widget buildFrame({Color activeColor, Color checkColor, ThemeData themeData}) {
return Material( return Material(
child: StatefulBuilder( child: Theme(
builder: (BuildContext context, StateSetter setState) { data: themeData ?? ThemeData(),
return Checkbox( child: StatefulBuilder(
value: true, builder: (BuildContext context, StateSetter setState) {
checkColor: color, return Checkbox(
onChanged: (bool value) { }, value: true,
); activeColor: activeColor,
}, checkColor: checkColor,
onChanged: (bool value) { },
);
},
),
), ),
); );
} }
...@@ -355,13 +359,21 @@ void main() { ...@@ -355,13 +359,21 @@ void main() {
return tester.renderObject<RenderToggleable>(find.byType(Checkbox)); return tester.renderObject<RenderToggleable>(find.byType(Checkbox));
} }
await tester.pumpWidget(buildFrame(null)); await tester.pumpWidget(buildFrame(checkColor: const Color(0xFFFFFFFF)));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(getCheckboxRenderer(), paints..path(color: const Color(0xFFFFFFFF))); // paints's color is 0xFFFFFFFF (default color) expect(getCheckboxRenderer(), paints..path(color: const Color(0xFFFFFFFF))); // paints's color is 0xFFFFFFFF (default color)
await tester.pumpWidget(buildFrame(const Color(0xFF000000))); await tester.pumpWidget(buildFrame(checkColor: const Color(0xFF000000)));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(getCheckboxRenderer(), paints..path(color: const Color(0xFF000000))); // paints's color is 0xFF000000 (params) expect(getCheckboxRenderer(), paints..path(color: const Color(0xFF000000))); // paints's color is 0xFF000000 (params)
await tester.pumpWidget(buildFrame(themeData: ThemeData(toggleableActiveColor: const Color(0xFF00FF00))));
await tester.pumpAndSettle();
expect(getCheckboxRenderer(), paints..rrect(color: const Color(0xFF00FF00))); // paints's color is 0xFF00FF00 (theme)
await tester.pumpWidget(buildFrame(activeColor: const Color(0xFF000000)));
await tester.pumpAndSettle();
expect(getCheckboxRenderer(), paints..rrect(color: const Color(0xFF000000))); // paints's color is 0xFF000000 (params)
}); });
} }
...@@ -19,21 +19,6 @@ Widget wrap({ Widget child }) { ...@@ -19,21 +19,6 @@ Widget wrap({ Widget child }) {
} }
void main() { void main() {
testWidgets('CheckboxListTile control test', (WidgetTester tester) async {
final List<dynamic> log = <dynamic>[];
await tester.pumpWidget(wrap(
child: CheckboxListTile(
value: true,
onChanged: (bool value) { log.add(value); },
title: const Text('Hello'),
),
));
await tester.tap(find.text('Hello'));
log.add('-');
await tester.tap(find.byType(Checkbox));
expect(log, equals(<dynamic>[false, '-', false]));
});
testWidgets('RadioListTile should initialize according to groupValue', (WidgetTester tester) async { testWidgets('RadioListTile should initialize according to groupValue', (WidgetTester tester) async {
final List<int> values = <int>[0, 1, 2]; final List<int> values = <int>[0, 1, 2];
int selectedValue; int selectedValue;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment