[CP-stable]Fixes tab semantics gets dropped if the child produce a semantics node (#169362)
This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request. ### Issue Link: What is the link to the issue this cherry-pick is addressing? https://github.com/flutter/flutter/issues/169175 ### Changelog Description: Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples Fixed unexpected crash when using Tab and TabBar widgets. ### Impact Description: What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch) app crash ### Workaround: Is there a workaround for this issue? Wrap the Tab widget with a MergeSemantics widget will mitigate the issue. ### Risk: What is the risk level of this cherry-pick? - [O] Low ### Test Coverage: Are you confident that your fix is well-tested by automated tests? - [O] Yes ### Validation Steps: What are the steps to validate that this fix works? create a TabBar that has a Tab with image widget ```dart TabBar( tabs: <Widget>[ Tab(icon: Image.network('https://some-url')), Tab(icon: Icon(Icons.beach_access_sharp)), Tab(icon: Icon(Icons.brightness_5_sharp)), ], ), ```
This commit is contained in:
parent
c56879b5f5
commit
7d3efe4643
@ -1976,6 +1976,7 @@ class _TabBarState extends State<TabBar> {
|
||||
),
|
||||
),
|
||||
);
|
||||
wrappedTabs[index] = MergeSemantics(child: wrappedTabs[index]);
|
||||
if (!widget.isScrollable && effectiveTabAlignment == TabAlignment.fill) {
|
||||
wrappedTabs[index] = Expanded(child: wrappedTabs[index]);
|
||||
}
|
||||
|
@ -4300,6 +4300,9 @@ class SemanticsOwner extends ChangeNotifier {
|
||||
return null;
|
||||
}
|
||||
if (node.mergeAllDescendantsIntoThisNode) {
|
||||
if (node._canPerformAction(action)) {
|
||||
return node._actions[action];
|
||||
}
|
||||
SemanticsNode? result;
|
||||
node._visitDescendants((SemanticsNode child) {
|
||||
if (child._canPerformAction(action)) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
// 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/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -156,6 +154,22 @@ void main() {
|
||||
expect(tester.renderObject(find.byType(CustomPaint)).debugNeedsPaint, true);
|
||||
});
|
||||
|
||||
testWidgets('tab semantics role test', (WidgetTester tester) async {
|
||||
// Regressing test for https://github.com/flutter/flutter/issues/169175
|
||||
// Creates an image semantics node with zero size.
|
||||
await tester.pumpWidget(
|
||||
boilerplate(
|
||||
child: DefaultTabController(
|
||||
length: 1,
|
||||
child: TabBar(
|
||||
tabs: <Widget>[Tab(icon: Semantics(image: true, child: const SizedBox.shrink()))],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(find.byType(Tab), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Tab sizing - icon', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
|
@ -918,6 +918,26 @@ void main() {
|
||||
expect(newNode.id, expectId);
|
||||
});
|
||||
|
||||
test('performActionAt can hit test on merged semantics node', () {
|
||||
bool tapped = false;
|
||||
final SemanticsOwner owner = SemanticsOwner(onSemanticsUpdate: (SemanticsUpdate update) {});
|
||||
final SemanticsNode root = SemanticsNode.root(owner: owner)
|
||||
..rect = const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0);
|
||||
final SemanticsNode merged = SemanticsNode()..rect = const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0);
|
||||
final SemanticsConfiguration mergeConfig =
|
||||
SemanticsConfiguration()
|
||||
..isSemanticBoundary = true
|
||||
..isMergingSemanticsOfDescendants = true
|
||||
..onTap = () => tapped = true;
|
||||
final SemanticsConfiguration rootConfig = SemanticsConfiguration()..isSemanticBoundary = true;
|
||||
|
||||
merged.updateWith(config: mergeConfig, childrenInInversePaintOrder: <SemanticsNode>[]);
|
||||
root.updateWith(config: rootConfig, childrenInInversePaintOrder: <SemanticsNode>[merged]);
|
||||
|
||||
owner.performActionAt(const Offset(5, 5), SemanticsAction.tap);
|
||||
expect(tapped, isTrue);
|
||||
});
|
||||
|
||||
test('Tags show up in debug properties', () {
|
||||
final SemanticsNode actionNode =
|
||||
SemanticsNode()..tags = <SemanticsTag>{RenderViewport.useTwoPaneSemantics};
|
||||
|
Loading…
x
Reference in New Issue
Block a user