Mayur Dhurpate
Mayur Dhurpate

Reputation: 1282

How to pass Taps to widgets below the top widget?

I'm trying to implement a very simple version of Card Paginator Component (single card) in Flutter.

Here is an example of a basic demo I've created:

class CardComponent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          top: 20.0,
          left: 20.0,
          child: 
          GestureDetector(
          // onTap should run while the text is visible on the screen
          // The text will become invisible when the Listview gest scrolled upwards
          onTap: (){print('text tapped');},
            child:
          Container(
          alignment:Alignment.topCenter,
          color: Colors.blueAccent,
        // This is fixed Text over which the card should scroll
        child: Text('Test Button')))),
        ListView(
          children: [
            //  This margin in first empty container pushes the whole card downward and makes the 'Test Button visible'
            Container(margin: EdgeInsets.only(top: 50.0)),
            // This is where the scrolling card actually starts
            Container(color: Colors.cyan[100], height: 120.0, width: 20.0),
            Container(color: Colors.cyan, height: 120.0, width: 20.0),
            Container(color: Colors.cyan[100], height: 120.0, width: 20.0),
            Container(color: Colors.cyan, height: 120.0, width: 20.0),
            Container(color: Colors.cyan[100], height: 120.0, width: 20.0),
            Container(color: Colors.cyan, height: 120.0, width: 20.0),
          ]
        )
      ],
    );
  }
}

The issue I'm facing is, I'm unable to click the button when the card in not scrolled up. The fixed 'Test Button' is visible on the screen because of the empty dummy Container pushing the scrollable ListView downwards. Yet, since the ListView covers the full screen by default, hence the onTap never runs on tapping the button when it's visible.

enter image description here

If I surround the ListView/SinglleChildScrollView with IgnorePointer class, the whole scrolling behaviour stops and also any taps to the children of the ListView stops working which is not desired.

How to tap on the button (backward widget in Stack) while allowing scrolling/tapping in ListView? Or should I approach building Card Paginator Component is some different way?

Upvotes: 6

Views: 4815

Answers (2)

Ovidiu
Ovidiu

Reputation: 8714

Potential duplicate of Flutter: How to make a ListView transparent to pointer events (but not its non-transparent contents)?

You need to wrap your empty Container within the ListView with a GestureDetector overriding onTapUp so that you can capture the tap position on the screen:

GestureDetector(
  onTapUp: (TapUpDetails tapUpDetails) {
    print("onTapUp global: " + tapUpDetails.globalPosition.toString());
  },

You then need to get the rectangle of the widget behind the ListView that you want to tap on, by using that widget's key:

RenderBox renderBox = _key.currentContext.findRenderObject();
Offset topLeftCorner = renderBox.localToGlobal(Offset.zero);
Size size = renderBox.size;
Rect rectangle = topLeftCorner & size;

And finally you can calculate whether the tap on the empty Container is within the rectangle of the widget behind, and at that point invoke your code as if you had a GestureDetector on the widget behind:

// if tap is within boundaries of the background widget
if (rectangle.contains(tapUpDetails.globalPosition)) {
  // your code here
}

Upvotes: 5

Aakash Kumar
Aakash Kumar

Reputation: 1187

I don't know if you want the fix bar height with button as per your current code but I can help you with the design as per your shared Card Paginator Component.

For that you can use CustomScrollView with SliverAppBar.

Here is the code

   CustomScrollView(
      slivers: <Widget>[
        SliverAppBar(
          backgroundColor: Colors.white,
          expandedHeight: 200,
          centerTitle: true,
          pinned: true,
          elevation: 0,
          flexibleSpace: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Expanded(
                child: Center(
                  child: Container(
                      padding: const EdgeInsets.all(10.0),
                      child: CircleAvatar(
                        backgroundColor: Colors.grey.shade400,
                        child: Image.asset("assets/user.png"),
                        maxRadius: 80,
                      )),
                ),
              ),
            ],
          ),
        ),
        SliverToBoxAdapter(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Center(child: Text("Aakash Kumar", style: Theme.of(context).textTheme.headline,)),
          ),
        ),
        SliverFixedExtentList(
          itemExtent: 150.0,
          delegate: SliverChildListDelegate(
            [
              Container(color: Colors.red),
              Container(color: Colors.purple),
              Container(color: Colors.green),
              Container(color: Colors.orange),
              Container(color: Colors.yellow),
              Container(color: Colors.pink),
            ],
          ),
        ),
      ],
    );

Hope this helps...

Upvotes: 2

Related Questions