fix(flutter): 화면 읽기 프로그램으로 누를 수 없던 버튼 6종 수정

Semantics(excludeSemantics: true) 로 감싼 버튼은 안쪽 InkWell 의 누르기 동작까지 지워져
TalkBack·VoiceOver 로 누를 수 없었다(하단 탭 · 언어 · 홈 검색창 · 카테고리 · 기준 위치 · 반려견 칩).
Semantics 에도 같은 onTap 을 준다. 기기 접근성 트리에서 누를 수 있음으로 바뀐 것을 확인했고,
누르기 동작이 빠지면 위젯 테스트가 실패한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-05 00:00:14 +09:00
parent 5caed15482
commit c6017fd0ed
8 changed files with 60 additions and 9 deletions
+2
View File
@@ -70,11 +70,13 @@ class _TabItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final color = selected ? AppColors.brand : AppColors.textTertiary;
// excludeSemantics 는 아래 InkResponse 의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
button: true,
selected: selected,
label: label,
excludeSemantics: true,
onTap: onTap,
child: InkResponse(
onTap: onTap,
radius: 36,
@@ -132,17 +132,21 @@ class _BaseLocationButton extends ConsumerWidget {
final label = fellBack
? kFallbackNeighborhood.label(l10n)
: choice.label(l10n);
Future<void> pickBase() async {
final picked = await showRegionSheet(context, selected: choice);
if (picked != null && context.mounted) {
await applyBaseLocation(context, ref, picked);
}
}
// excludeSemantics 는 InkWell 의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
button: true,
label: l10n.baseLocationButtonLabel(label),
excludeSemantics: true,
onTap: pickBase,
child: InkWell(
onTap: () async {
final picked = await showRegionSheet(context, selected: choice);
if (picked != null && context.mounted) {
await applyBaseLocation(context, ref, picked);
}
},
onTap: pickBase,
child: SizedBox(
height: 32,
child: Row(
@@ -115,10 +115,12 @@ class _CategoryCell extends StatelessWidget {
@override
Widget build(BuildContext context) {
final label = shortcut.label(context.l10n);
// excludeSemantics 는 InkWell 의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
button: true,
label: label,
excludeSemantics: true,
onTap: onTap,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
@@ -14,16 +14,19 @@ class HomeSearchBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final hint = context.l10n.searchHint;
void openSearch() => context.push(AppRoutes.placeSearch(focus: true));
// excludeSemantics 는 InkWell 의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
button: true,
label: hint,
excludeSemantics: true,
onTap: openSearch,
child: Material(
color: AppColors.inputFill,
borderRadius: BorderRadius.circular(kRadius),
child: InkWell(
borderRadius: BorderRadius.circular(kRadius),
onTap: () => context.push(AppRoutes.placeSearch(focus: true)),
onTap: openSearch,
child: SizedBox(
height: 48,
child: Row(
@@ -427,17 +427,20 @@ class FilterToggleChip extends StatelessWidget {
color: selected ? AppColors.chipBorderSelected : AppColors.chipBorder,
),
);
void toggle() => onChanged(!selected);
// excludeSemantics 는 InkWell 의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
toggled: selected,
button: true,
excludeSemantics: true,
label: label,
onTap: toggle,
child: Material(
color: selected ? AppColors.brandSoft : AppColors.background,
shape: shape,
child: InkWell(
customBorder: shape,
onTap: () => onChanged(!selected),
onTap: toggle,
child: Container(
height: 36,
padding: const EdgeInsets.symmetric(horizontal: 12),
@@ -16,12 +16,15 @@ class LanguageButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = context.l10n;
void openSheet() => _openSheet(context, ref);
// excludeSemantics 는 버튼의 누르기 동작까지 지운다 — 화면 읽기 프로그램이 누를 수 있게 onTap 을 함께 준다
return Semantics(
button: true,
label: l10n.languageButtonLabel(l10n.languageName),
excludeSemantics: true,
onTap: openSheet,
child: OutlinedButton(
onPressed: () => _openSheet(context, ref),
onPressed: openSheet,
style: OutlinedButton.styleFrom(
minimumSize: Size(44, compact ? 44 : 40),
padding: EdgeInsets.only(left: 12, right: compact ? 12 : 10),