模態路由中 Overlay Entry 的語義順序
摘要
#我們變更了模態路由中 overlay entries 的語義遍歷順序。輔助功能語音回饋或螢幕閱讀器現在會先聚焦在模態路由的範圍,而不是它的模態阻擋層。
背景
#模態路由有兩個 overlay entries:範圍和模態阻擋層。範圍是模態路由的實際內容,而模態阻擋層是路由的背景,如果其範圍沒有覆蓋整個螢幕。如果模態路由的 barrierDismissible
返回 true,則模態阻擋層會變成輔助功能可聚焦的,因為使用者可以點擊模態阻擋層來關閉模態路由。這個變更特別讓輔助功能先聚焦在範圍,然後才是模態阻擋層。
變更描述
#我們在模態路由的兩個 overlay entries 上方添加了額外的語義節點。這些語義節點表示這兩個 overlay entries 的語義遍歷順序。這也改變了語義樹的結構。
遷移指南
#如果您的測試在更新後由於語義樹的變更而開始失敗,您可以通過預期模態路由 overlay entries 上方的新節點來遷移您的程式碼。
遷移前的程式碼
dart
import 'dart:ui';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
void main() {
testWidgets('example test', (WidgetTester tester) async {
final SemanticsHandle handle =
tester.binding.pipelineOwner.ensureSemantics();
// Build our app and trigger a frame.
await tester.pumpWidget(MaterialApp(home: Scaffold(body: Text('test'))));
final SemanticsNode root =
tester.binding.pipelineOwner.semanticsOwner.rootSemanticsNode;
final SemanticsNode firstNode = getChild(root);
expect(firstNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
// Fixes the test by expecting an additional node above the scope route.
final SemanticsNode secondNode = getChild(firstNode);
expect(secondNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
final SemanticsNode thirdNode = getChild(secondNode);
expect(thirdNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
expect(thirdNode.hasFlag(SemanticsFlag.scopesRoute), true);
final SemanticsNode forthNode = getChild(thirdNode);
expect(forthNode.rect, Rect.fromLTRB(0.0, 0.0, 56.0, 14.0));
expect(forthNode.label, 'test');
handle.dispose();
});
}
SemanticsNode getChild(SemanticsNode node) {
SemanticsNode child;
bool visiter(SemanticsNode target) {
child = target;
return false;
}
node.visitChildren(visiter);
return child;
}
遷移後的程式碼
dart
import 'dart:ui';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
void main() {
testWidgets('example test', (WidgetTester tester) async {
final SemanticsHandle handle =
tester.binding.pipelineOwner.ensureSemantics();
// Build our app and trigger a frame.
await tester.pumpWidget(MaterialApp(home: Scaffold(body: Text('test'))));
final SemanticsNode root =
tester.binding.pipelineOwner.semanticsOwner.rootSemanticsNode;
final SemanticsNode firstNode = getChild(root);
expect(firstNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
// Fixes the test by expecting an additional node above the scope route.
final SemanticsNode secondNode = getChild(firstNode);
expect(secondNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
final SemanticsNode thirdNode = getChild(secondNode);
expect(thirdNode.rect, Rect.fromLTRB(0.0, 0.0, 800.0, 600.0));
expect(thirdNode.hasFlag(SemanticsFlag.scopesRoute), true);
final SemanticsNode forthNode = getChild(thirdNode);
expect(forthNode.rect, Rect.fromLTRB(0.0, 0.0, 56.0, 14.0));
expect(forthNode.label, 'test');
handle.dispose();
});
}
SemanticsNode getChild(SemanticsNode node) {
SemanticsNode child;
bool visiter(SemanticsNode target) {
child = target;
return false;
}
node.visitChildren(visiter);
return child;
}
時程
#於版本中加入:1.19.0
在穩定版本中:1.20
參考資料
#API 文件
相關議題
相關 PR
除非另有說明,否則本網站上的文件反映了 Flutter 的最新穩定版本。頁面最後更新於 2024-04-04。 檢視原始碼 或 回報問題。