diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 682bd9ef54e..3b51f0660b5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09d05a38912a3c1a906e95099cac9a7e14fae85f +232060828a1d4a9c3ee16b92f3af5f5a15041e32 diff --git a/packages/flutter/lib/src/rendering/custom_paint.dart b/packages/flutter/lib/src/rendering/custom_paint.dart index f0ac0eebadb..20ebbf216cc 100644 --- a/packages/flutter/lib/src/rendering/custom_paint.dart +++ b/packages/flutter/lib/src/rendering/custom_paint.dart @@ -834,6 +834,9 @@ class RenderCustomPaint extends RenderProxyBox { if (properties.obscured != null) { config.isObscured = properties.obscured; } + if (properties.hidden != null) { + config.isHidden = properties.hidden; + } if (properties.header != null) { config.isHeader = properties.header; } diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 24710f6a40e..a3c79fe47f7 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -3021,6 +3021,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox { bool obscured, bool scopesRoute, bool namesRoute, + bool hidden, String label, String value, String increasedValue, @@ -3058,6 +3059,7 @@ class RenderSemanticsAnnotations extends RenderProxyBox { _obscured = obscured, _scopesRoute = scopesRoute, _namesRoute = namesRoute, + _hidden = hidden, _label = label, _value = value, _increasedValue = increasedValue, @@ -3237,6 +3239,17 @@ class RenderSemanticsAnnotations extends RenderProxyBox { markNeedsSemanticsUpdate(); } + /// If non-null, sets the [SemanticsNode.isHidden] semantic to the given + /// value. + bool get hidden => _hidden; + bool _hidden; + set hidden(bool value) { + if (hidden == value) + return; + _hidden = value; + markNeedsSemanticsUpdate(); + } + /// If non-null, sets the [SemanticsNode.label] semantic to the given value. /// /// The reading direction is given by [textDirection]. @@ -3678,6 +3691,8 @@ class RenderSemanticsAnnotations extends RenderProxyBox { config.isInMutuallyExclusiveGroup = inMutuallyExclusiveGroup; if (obscured != null) config.isObscured = obscured; + if (hidden != null) + config.isHidden = hidden; if (label != null) config.label = label; if (value != null) diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index a4170e27fdb..0ef43530671 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -319,6 +319,7 @@ class SemanticsProperties extends DiagnosticableTree { this.textField, this.focused, this.inMutuallyExclusiveGroup, + this.hidden, this.obscured, this.scopesRoute, this.namesRoute, @@ -401,7 +402,25 @@ class SemanticsProperties extends DiagnosticableTree { /// For example, a radio button is in a mutually exclusive group because only /// one radio button in that group can be marked as [checked]. final bool inMutuallyExclusiveGroup; - + + /// If non-null, whether the node is considered hidden. + /// + /// Hidden elements are currently not visible on screen. They may be covered + /// by other elements or positioned outside of the visible area of a viewport. + /// + /// Hidden elements cannot gain accessibility focus though regular touch. The + /// only way they can be focused is by moving the focus to them via linear + /// navigation. + /// + /// Platforms are free to completely ignore hidden elements and new platforms + /// are encouraged to do so. + /// + /// Instead of marking an element as hidden it should usually be excluded from + /// the semantics tree altogether. Hidden elements are only included in the + /// semantics tree to work around platform limitations and they are mainly + /// used to implement accessibility scrolling on iOS. + final bool hidden; + /// If non-null, whether [value] should be obscured. /// /// This option is usually set in combination with [textField] to indicate @@ -1442,6 +1461,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin { final List flags = SemanticsFlag.values.values.where((SemanticsFlag flag) => _hasFlag(flag)).map((SemanticsFlag flag) => flag.toString().substring('SemanticsFlag.'.length)).toList(); properties.add(new IterableProperty('flags', flags, ifEmpty: null)); properties.add(new FlagProperty('isInvisible', value: isInvisible, ifTrue: 'invisible')); + properties.add(new FlagProperty('isHidden', value: _hasFlag(SemanticsFlag.isHidden), ifTrue: 'HIDDEN')); properties.add(new StringProperty('label', _label, defaultValue: '')); properties.add(new StringProperty('value', _value, defaultValue: '')); properties.add(new StringProperty('increasedValue', _increasedValue, defaultValue: '')); @@ -2450,6 +2470,27 @@ class SemanticsConfiguration { _setFlag(SemanticsFlag.isHeader, value); } + /// Whether the owning [RenderObject] is considered hidden. + /// + /// Hidden elements are currently not visible on screen. They may be covered + /// by other elements or positioned outside of the visible area of a viewport. + /// + /// Hidden elements cannot gain accessibility focus though regular touch. The + /// only way they can be focused is by moving the focus to them via linear + /// navigation. + /// + /// Platforms are free to completely ignore hidden elements and new platforms + /// are encouraged to do so. + /// + /// Instead of marking an element as hidden it should usually be excluded from + /// the semantics tree altogether. Hidden elements are only included in the + /// semantics tree to work around platform limitations and they are mainly + /// used to implement accessibility scrolling on iOS. + bool get isHidden => _hasFlag(SemanticsFlag.isHidden); + set isHidden(bool value) { + _setFlag(SemanticsFlag.isHidden, value); + } + /// Whether the owning [RenderObject] is a text field. bool get isTextField => _hasFlag(SemanticsFlag.isTextField); set isTextField(bool value) { diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 68571fb05ee..80965e5e83a 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -4898,6 +4898,7 @@ class Semantics extends SingleChildRenderObjectWidget { bool obscured, bool scopesRoute, bool namesRoute, + bool hidden, String label, String value, String increasedValue, @@ -4938,6 +4939,7 @@ class Semantics extends SingleChildRenderObjectWidget { obscured: obscured, scopesRoute: scopesRoute, namesRoute: namesRoute, + hidden: hidden, label: label, value: value, increasedValue: increasedValue, @@ -5023,6 +5025,7 @@ class Semantics extends SingleChildRenderObjectWidget { obscured: properties.obscured, scopesRoute: properties.scopesRoute, namesRoute: properties.namesRoute, + hidden: properties.hidden, label: properties.label, value: properties.value, increasedValue: properties.increasedValue, @@ -5065,16 +5068,23 @@ class Semantics extends SingleChildRenderObjectWidget { void updateRenderObject(BuildContext context, RenderSemanticsAnnotations renderObject) { renderObject ..container = container + ..scopesRoute = properties.scopesRoute ..explicitChildNodes = explicitChildNodes ..enabled = properties.enabled ..checked = properties.checked ..selected = properties.selected + ..button = properties.button + ..header = properties.header + ..textField = properties.textField + ..focused = properties.focused + ..inMutuallyExclusiveGroup = properties.inMutuallyExclusiveGroup + ..obscured = properties.obscured + ..hidden = properties.hidden ..label = properties.label ..value = properties.value ..increasedValue = properties.increasedValue ..decreasedValue = properties.decreasedValue ..hint = properties.hint - ..scopesRoute = properties.scopesRoute ..namesRoute = properties.namesRoute ..textDirection = _getTextDirection(context) ..sortKey = properties.sortKey diff --git a/packages/flutter/test/semantics/semantics_test.dart b/packages/flutter/test/semantics/semantics_test.dart index 0f98d79ce59..5cd82a9dcfb 100644 --- a/packages/flutter/test/semantics/semantics_test.dart +++ b/packages/flutter/test/semantics/semantics_test.dart @@ -361,6 +361,7 @@ void main() { ' actions: []\n' ' flags: []\n' ' invisible\n' + ' isHidden: false\n' ' label: ""\n' ' value: ""\n' ' increasedValue: ""\n' diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index e50730c0e2d..a757d1db48c 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -410,6 +410,7 @@ void _defineTests() { enabled: true, checked: true, selected: true, + hidden: true, button: true, textField: true, focused: true, diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index 730124e1b34..9ada05d1404 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -461,8 +461,10 @@ void main() { await tester.pumpWidget( new Semantics( container: true, + explicitChildNodes: true, // flags enabled: true, + hidden: true, checked: true, selected: true, button: true, @@ -473,11 +475,10 @@ void main() { obscured: true, scopesRoute: true, namesRoute: true, - explicitChildNodes: true, ) ); - final TestSemantics expectedSemantics = new TestSemantics.root( + TestSemantics expectedSemantics = new TestSemantics.root( children: [ new TestSemantics.rootChild( rect: TestSemantics.fullScreen, @@ -487,6 +488,19 @@ void main() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); + await tester.pumpWidget(new Semantics( + container: true, + )); + expectedSemantics = new TestSemantics.root( + children: [ + new TestSemantics.rootChild( + rect: TestSemantics.fullScreen, + flags: [], + ), + ], + ); + expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); + semantics.dispose(); });