0

How can I make parent widget's onTap and child widget's onTap to be called together?

I have a page which consist of several widgets which has their own onTap. One of the component is a TextField and when it is tapped, keyboard is opened. I want to close that keyboard when user taps outside of this TextField. But the child widget's onTap is triggered and parent's onTap is not.

When child onTap wins and opens a new page, if you navigate back, keyboard is opened again. How can I solve this issue?

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,
      ),
    );
  }
}
Figen Güngör
  • 12,169
  • 14
  • 66
  • 108

3 Answers3

0

Wrap the parent widget with gesture detector. I think that solely will work. There is no need to wrap child with gesture detector if you have to call the same method.

0

You can use a FocusNode for this. First you need to initialise the Focusnode:

FocusNode focusNode = FocusNode();

Then you pass it to the textfield:

TextField(focusNode: focusNode)

Finally, you unfocus the textfield when the parent is clicked:

focusNode.unfocus();

So when applied to your example code, you get:

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,
              ),
            ),
          )),
        ),
      ),
    );
  }
}

(I put two classes in one, just to keep the code compact)

Wouter
  • 769
  • 3
  • 9
0

Check first- is the keyboard open if it is focus then only apply this code to close the keyboard on your tap event.

onTap: () {
    FocusScopeNode currentFocus = FocusScope.of(context);
    if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
       currentFocus.focusedChild.unfocus();
    }
}
Vishal_VE
  • 1,852
  • 1
  • 6
  • 9