mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Identify CheckBox and RadioButton as such (#14087)
* Identify CHeckBox and RadioButton as such * review feedback
This commit is contained in:
parent
18c60d3301
commit
15af86459d
|
@ -1 +1 @@
|
||||||
05fe72d068e19c7886e8d27f9b004201d5ad1300
|
e7e94c6307bcefdbd4835a6f1a594a70df5dfe9a
|
||||||
|
|
|
@ -118,15 +118,12 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterial(context));
|
assert(debugCheckHasMaterial(context));
|
||||||
final ThemeData themeData = Theme.of(context);
|
final ThemeData themeData = Theme.of(context);
|
||||||
return new Semantics(
|
return new _RadioRenderObjectWidget(
|
||||||
checked: widget.value == widget.groupValue,
|
selected: widget.value == widget.groupValue,
|
||||||
child: new _RadioRenderObjectWidget(
|
activeColor: widget.activeColor ?? themeData.accentColor,
|
||||||
selected: widget.value == widget.groupValue,
|
inactiveColor: _getInactiveColor(themeData),
|
||||||
activeColor: widget.activeColor ?? themeData.accentColor,
|
onChanged: _enabled ? _handleChanged : null,
|
||||||
inactiveColor: _getInactiveColor(themeData),
|
vsync: this,
|
||||||
onChanged: _enabled ? _handleChanged : null,
|
|
||||||
vsync: this,
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,9 +184,6 @@ class _RenderRadio extends RenderToggleable {
|
||||||
vsync: vsync,
|
vsync: vsync,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
|
||||||
bool get isInteractive => super.isInteractive && !value;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(PaintingContext context, Offset offset) {
|
void paint(PaintingContext context, Offset offset) {
|
||||||
final Canvas canvas = context.canvas;
|
final Canvas canvas = context.canvas;
|
||||||
|
@ -212,4 +206,10 @@ class _RenderRadio extends RenderToggleable {
|
||||||
canvas.drawCircle(center, _kInnerRadius * position.value, paint);
|
canvas.drawCircle(center, _kInnerRadius * position.value, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
|
super.describeSemanticsConfiguration(config);
|
||||||
|
config.isInMutuallyExclusiveGroup = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,8 @@ abstract class RenderToggleable extends RenderConstrainedBox {
|
||||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
|
|
||||||
config.isSemanticBoundary = isInteractive;
|
config.isSemanticBoundary = true;
|
||||||
|
config.isEnabled = isInteractive;
|
||||||
if (isInteractive)
|
if (isInteractive)
|
||||||
config.onTap = _handleTap;
|
config.onTap = _handleTap;
|
||||||
config.isChecked = _value;
|
config.isChecked = _value;
|
||||||
|
|
|
@ -1099,6 +1099,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||||
properties.add(new FlagProperty('isEnabled', value: _hasFlag(SemanticsFlag.isEnabled), ifFalse: 'disabled'));
|
properties.add(new FlagProperty('isEnabled', value: _hasFlag(SemanticsFlag.isEnabled), ifFalse: 'disabled'));
|
||||||
if (_hasFlag(SemanticsFlag.hasCheckedState))
|
if (_hasFlag(SemanticsFlag.hasCheckedState))
|
||||||
properties.add(new FlagProperty('isChecked', value: _hasFlag(SemanticsFlag.isChecked), ifTrue: 'checked', ifFalse: 'unchecked'));
|
properties.add(new FlagProperty('isChecked', value: _hasFlag(SemanticsFlag.isChecked), ifTrue: 'checked', ifFalse: 'unchecked'));
|
||||||
|
properties.add(new FlagProperty('isInMutuallyExcusiveGroup', value: _hasFlag(SemanticsFlag.isInMutuallyExclusiveGroup), ifTrue: 'mutually-exclusive'));
|
||||||
properties.add(new FlagProperty('isSelected', value: _hasFlag(SemanticsFlag.isSelected), ifTrue: 'selected'));
|
properties.add(new FlagProperty('isSelected', value: _hasFlag(SemanticsFlag.isSelected), ifTrue: 'selected'));
|
||||||
properties.add(new FlagProperty('isFocused', value: _hasFlag(SemanticsFlag.isFocused), ifTrue: 'focused'));
|
properties.add(new FlagProperty('isFocused', value: _hasFlag(SemanticsFlag.isFocused), ifTrue: 'focused'));
|
||||||
properties.add(new FlagProperty('isButton', value: _hasFlag(SemanticsFlag.isButton), ifTrue: 'button'));
|
properties.add(new FlagProperty('isButton', value: _hasFlag(SemanticsFlag.isButton), ifTrue: 'button'));
|
||||||
|
@ -1790,6 +1791,16 @@ class SemanticsConfiguration {
|
||||||
_setFlag(SemanticsFlag.isChecked, value);
|
_setFlag(SemanticsFlag.isChecked, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the owning RenderObject corresponds to UI that allows the user to
|
||||||
|
/// pick one of several mutually exclusive options.
|
||||||
|
///
|
||||||
|
/// For example, a [Radio] button is in a mutually exclusive group because
|
||||||
|
/// only one radio button in that group can be marked as [isChecked].
|
||||||
|
bool get isInMutuallyExclusiveGroup => _hasFlag(SemanticsFlag.isInMutuallyExclusiveGroup);
|
||||||
|
set isInMutuallyExclusiveGroup(bool value) {
|
||||||
|
_setFlag(SemanticsFlag.isInMutuallyExclusiveGroup, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the owning [RenderObject] currently holds the user's focus.
|
/// Whether the owning [RenderObject] currently holds the user's focus.
|
||||||
bool get isFocused => _hasFlag(SemanticsFlag.isFocused);
|
bool get isFocused => _hasFlag(SemanticsFlag.isFocused);
|
||||||
set isFocused(bool value) {
|
set isFocused(bool value) {
|
||||||
|
|
|
@ -115,7 +115,7 @@ class BannerPainter extends CustomPainter {
|
||||||
void _prepare() {
|
void _prepare() {
|
||||||
_paintShadow = new Paint()
|
_paintShadow = new Paint()
|
||||||
..color = const Color(0x7F000000)
|
..color = const Color(0x7F000000)
|
||||||
..maskFilter = new MaskFilter.blur(BlurStyle.normal, 4.0);
|
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4.0);
|
||||||
_paintBanner = new Paint()
|
_paintBanner = new Paint()
|
||||||
..color = color;
|
..color = color;
|
||||||
_textPainter = new TextPainter(
|
_textPainter = new TextPainter(
|
||||||
|
|
105
packages/flutter/test/material/checkbox_test.dart
Normal file
105
packages/flutter/test/material/checkbox_test.dart
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2017 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 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('CheckBox semantics', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
|
await tester.pumpWidget(new Material(
|
||||||
|
child: new Checkbox(
|
||||||
|
value: false,
|
||||||
|
onChanged: (bool b) { },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(new Material(
|
||||||
|
child: new Checkbox(
|
||||||
|
value: true,
|
||||||
|
onChanged: (bool b) { },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.isChecked,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(const Material(
|
||||||
|
child: const Checkbox(
|
||||||
|
value: false,
|
||||||
|
onChanged: null,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(const Material(
|
||||||
|
child: const Checkbox(
|
||||||
|
value: true,
|
||||||
|
onChanged: null,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.isChecked,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
|
}
|
|
@ -99,6 +99,7 @@ void main() {
|
||||||
expect(semantics, hasSemantics(new TestSemantics.root(
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
children: <TestSemantics>[
|
children: <TestSemantics>[
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: null,
|
transform: null,
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
|
@ -111,6 +112,7 @@ void main() {
|
||||||
label: 'aaa\nAAA',
|
label: 'aaa\nAAA',
|
||||||
),
|
),
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
|
id: 3,
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
|
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
|
@ -123,18 +125,20 @@ void main() {
|
||||||
label: 'bbb\nBBB',
|
label: 'bbb\nBBB',
|
||||||
),
|
),
|
||||||
new TestSemantics.rootChild(
|
new TestSemantics.rootChild(
|
||||||
|
id: 5,
|
||||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||||
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
|
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
|
||||||
flags: <SemanticsFlag>[
|
flags: <SemanticsFlag>[
|
||||||
SemanticsFlag.hasCheckedState,
|
SemanticsFlag.hasCheckedState,
|
||||||
SemanticsFlag.hasEnabledState,
|
SemanticsFlag.hasEnabledState,
|
||||||
SemanticsFlag.isEnabled
|
SemanticsFlag.isEnabled,
|
||||||
|
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||||
],
|
],
|
||||||
actions: SemanticsAction.tap.index,
|
actions: SemanticsAction.tap.index,
|
||||||
label: 'CCC\nccc',
|
label: 'CCC\nccc',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
), ignoreId: true));
|
)));
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,14 @@
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('Radio control test', (WidgetTester tester) async {
|
testWidgets('Radio control test', (WidgetTester tester) async {
|
||||||
final Key key = new UniqueKey();
|
final Key key = new UniqueKey();
|
||||||
|
@ -57,4 +62,104 @@ void main() {
|
||||||
|
|
||||||
expect(log, isEmpty);
|
expect(log, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Radio semantics', (WidgetTester tester) async {
|
||||||
|
final SemanticsTester semantics = new SemanticsTester(tester);
|
||||||
|
|
||||||
|
await tester.pumpWidget(new Material(
|
||||||
|
child: new Radio<int>(
|
||||||
|
value: 1,
|
||||||
|
groupValue: 2,
|
||||||
|
onChanged: (int i) { },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(new Material(
|
||||||
|
child: new Radio<int>(
|
||||||
|
value: 2,
|
||||||
|
groupValue: 2,
|
||||||
|
onChanged: (int i) { },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.isChecked,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
SemanticsFlag.isEnabled,
|
||||||
|
],
|
||||||
|
actions: <SemanticsAction>[
|
||||||
|
SemanticsAction.tap,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(const Material(
|
||||||
|
child: const Radio<int>(
|
||||||
|
value: 1,
|
||||||
|
groupValue: 2,
|
||||||
|
onChanged: null,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
await tester.pumpWidget(const Material(
|
||||||
|
child: const Radio<int>(
|
||||||
|
value: 2,
|
||||||
|
groupValue: 2,
|
||||||
|
onChanged: null,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
expect(semantics, hasSemantics(new TestSemantics.root(
|
||||||
|
children: <TestSemantics>[
|
||||||
|
new TestSemantics.rootChild(
|
||||||
|
id: 1,
|
||||||
|
flags: <SemanticsFlag>[
|
||||||
|
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||||
|
SemanticsFlag.hasCheckedState,
|
||||||
|
SemanticsFlag.isChecked,
|
||||||
|
SemanticsFlag.hasEnabledState,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
), ignoreRect: true, ignoreTransform: true));
|
||||||
|
|
||||||
|
semantics.dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,7 +206,7 @@ void main() {
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
|
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
|
||||||
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, isFocused: false, isButton: false, isTextField: false, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null)\n'
|
'SemanticsNode#1(owner: null, isMergedIntoParent: false, mergeAllDescendantsIntoThisNode: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isInMutuallyExcusiveGroup: false, isSelected: false, isFocused: false, isButton: false, isTextField: false, label: "", value: "", increasedValue: "", decreasedValue: "", hint: "", textDirection: null)\n'
|
||||||
);
|
);
|
||||||
|
|
||||||
final SemanticsConfiguration config = new SemanticsConfiguration()
|
final SemanticsConfiguration config = new SemanticsConfiguration()
|
||||||
|
|
Loading…
Reference in a new issue