mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +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) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
return new Semantics(
|
||||
checked: widget.value == widget.groupValue,
|
||||
child: new _RadioRenderObjectWidget(
|
||||
selected: widget.value == widget.groupValue,
|
||||
activeColor: widget.activeColor ?? themeData.accentColor,
|
||||
inactiveColor: _getInactiveColor(themeData),
|
||||
onChanged: _enabled ? _handleChanged : null,
|
||||
vsync: this,
|
||||
)
|
||||
return new _RadioRenderObjectWidget(
|
||||
selected: widget.value == widget.groupValue,
|
||||
activeColor: widget.activeColor ?? themeData.accentColor,
|
||||
inactiveColor: _getInactiveColor(themeData),
|
||||
onChanged: _enabled ? _handleChanged : null,
|
||||
vsync: this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -187,9 +184,6 @@ class _RenderRadio extends RenderToggleable {
|
|||
vsync: vsync,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get isInteractive => super.isInteractive && !value;
|
||||
|
||||
@override
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
final Canvas canvas = context.canvas;
|
||||
|
@ -212,4 +206,10 @@ class _RenderRadio extends RenderToggleable {
|
|||
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) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
|
||||
config.isSemanticBoundary = isInteractive;
|
||||
config.isSemanticBoundary = true;
|
||||
config.isEnabled = isInteractive;
|
||||
if (isInteractive)
|
||||
config.onTap = _handleTap;
|
||||
config.isChecked = _value;
|
||||
|
|
|
@ -1099,6 +1099,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||
properties.add(new FlagProperty('isEnabled', value: _hasFlag(SemanticsFlag.isEnabled), ifFalse: 'disabled'));
|
||||
if (_hasFlag(SemanticsFlag.hasCheckedState))
|
||||
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('isFocused', value: _hasFlag(SemanticsFlag.isFocused), ifTrue: 'focused'));
|
||||
properties.add(new FlagProperty('isButton', value: _hasFlag(SemanticsFlag.isButton), ifTrue: 'button'));
|
||||
|
@ -1790,6 +1791,16 @@ class SemanticsConfiguration {
|
|||
_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.
|
||||
bool get isFocused => _hasFlag(SemanticsFlag.isFocused);
|
||||
set isFocused(bool value) {
|
||||
|
|
|
@ -115,7 +115,7 @@ class BannerPainter extends CustomPainter {
|
|||
void _prepare() {
|
||||
_paintShadow = new Paint()
|
||||
..color = const Color(0x7F000000)
|
||||
..maskFilter = new MaskFilter.blur(BlurStyle.normal, 4.0);
|
||||
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 4.0);
|
||||
_paintBanner = new Paint()
|
||||
..color = color;
|
||||
_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(
|
||||
children: <TestSemantics>[
|
||||
new TestSemantics.rootChild(
|
||||
id: 1,
|
||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||
transform: null,
|
||||
flags: <SemanticsFlag>[
|
||||
|
@ -111,6 +112,7 @@ void main() {
|
|||
label: 'aaa\nAAA',
|
||||
),
|
||||
new TestSemantics.rootChild(
|
||||
id: 3,
|
||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
|
||||
flags: <SemanticsFlag>[
|
||||
|
@ -123,18 +125,20 @@ void main() {
|
|||
label: 'bbb\nBBB',
|
||||
),
|
||||
new TestSemantics.rootChild(
|
||||
id: 5,
|
||||
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
|
||||
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
|
||||
flags: <SemanticsFlag>[
|
||||
SemanticsFlag.hasCheckedState,
|
||||
SemanticsFlag.hasEnabledState,
|
||||
SemanticsFlag.isEnabled
|
||||
SemanticsFlag.isEnabled,
|
||||
SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||
],
|
||||
actions: SemanticsAction.tap.index,
|
||||
label: 'CCC\nccc',
|
||||
),
|
||||
],
|
||||
), ignoreId: true));
|
||||
)));
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
// 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('Radio control test', (WidgetTester tester) async {
|
||||
final Key key = new UniqueKey();
|
||||
|
@ -57,4 +62,104 @@ void main() {
|
|||
|
||||
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(
|
||||
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()
|
||||
|
|
Loading…
Reference in a new issue