Как вызвать и родительский, и дочерний элемент при касании GestureDetector
Как я могу заставить родительский виджет onTap и дочерний виджет onTap вызываться вместе?
У меня есть страница, состоящая из нескольких виджетов, у которых есть собственный onTap. Одним из компонентов является TextField, и при нажатии на него открывается клавиатура. Я хочу закрыть эту клавиатуру, когда пользователь нажимает за пределами этого текстового поля. Но onTap дочернего виджета запускается, а родительский onTap - нет.
Когда дочерний элемент onTap выигрывает и открывает новую страницу, если вы вернетесь назад, клавиатура снова откроется. Как я могу решить эту проблему?
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: ParentClicky(),
);
}
}
class ParentClicky extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () => print('PARENT CLICKED'),
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.pink,
child: Center(child: ChildClicky()),
),
),
);
}
}
class ChildClicky extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => print('CHILD CLICKED'),
child: Container(
width: 100,
height: 100,
color: Colors.yellow,
),
);
}
}
3 ответа
Для этого вы можете использовать FocusNode. Сначала вам нужно инициализировать Focusnode:
FocusNode focusNode = FocusNode();
Затем вы передаете его в текстовое поле:
TextField(focusNode: focusNode)
Наконец, вы расфокусируете текстовое поле при щелчке родителя:
focusNode.unfocus();
Итак, применительно к вашему примеру кода вы получаете:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: ParentClicky(),
);
}
}
class ParentClicky extends StatelessWidget {
FocusNode focusNode = FocusNode();
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
print('PARENT CLICKED');
focusNode.unfocus();
},
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.pink,
child: Center(
child: GestureDetector(
onTap: () => print('CHILD CLICKED'),
child: Container(
width: 100,
height: 100,
color: Colors.yellow,
child: TextField(
focusNode: focusNode,
),
),
)),
),
),
);
}
}
(Я поместил два класса в один, просто чтобы код был компактным)
Сначала проверьте, открыта ли клавиатура, если она находится в фокусе, а затем примените этот код только для закрытия клавиатуры при событии касания.
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
currentFocus.focusedChild.unfocus();
}
}
Оберните родительский виджет детектором жестов. Я думаю, что только это будет работать. Нет необходимости оборачивать дочерний элемент детектором жестов, если вам нужно вызвать тот же метод.