Как вызвать и родительский, и дочерний элемент при касании 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();
    }
}

Оберните родительский виджет детектором жестов. Я думаю, что только это будет работать. Нет необходимости оборачивать дочерний элемент детектором жестов, если вам нужно вызвать тот же метод.

Другие вопросы по тегам