Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform Gesture Detector in Flutter(with Stack)

Tags:

flutter

dart

In my code, I use a gesture detector to pull up my menu as the user is dragging. But when I pull the menu up, the hitbox of the GestureDetector doesn't change, so when I want to put it back down it only registers dragging on the initial hitbox, not the new one(where I transformed the widget to)

I hope you can understand this^^

Here's the code:

Stack(children: [
  Column(
    children: <Widget>[
      Expanded(
          child: TabBarView(children: <Widget>[
        CostumCard(
          imgUrl: url,
        ),
        CostumCard(
          imgUrl: url,
        ),
      ]))
    ],
  ),
  IgnorePointer(
    child: Opacity(
      opacity: opacity,
      child: Container(color: Colors.black),
    ),
  ),
  Transform(
    transformHitTests: true,
    transform: Matrix4.translationValues(
        0.0, MediaQuery.of(context).size.height - 80 - 70, 0.0),
    child: Transform(
      transformHitTests: true,
      transform: Matrix4.translationValues(0.0, yTransform, 0.0),
      child: GestureDetector(
        onVerticalDragStart: (DragStartDetails details) {
          dragStartY = details.globalPosition.dy;
          dragUpdateY = dragStartY;
        },
        onVerticalDragUpdate: (DragUpdateDetails details) {
          dragDifference =
              dragUpdateY - details.globalPosition.dy;
          yTransform -= dragDifference;
          yTransform = yTransform.clamp(-400.0, 0.0);
          setState(() {
            if (yTransform <= -400)
              yTransform = -400.0;
            else if (yTransform >= 0)
              yTransform = 0.0;
            else
              yTransform = yTransform;
            opacity = yTransform / -400 * 0.8;
            rotation = yTransform / -400 * PI;
          });
          dragUpdateY = details.globalPosition.dy;
        },
        onVerticalDragEnd: (DragEndDetails details) {
          if (dragStartY - dragUpdateY >= 100) {
            setState(() {
              yTransform = -400.0;
              opacity = yTransform / -400 * 0.8;
              rotation = yTransform / -400 * PI;
            });
          } else if (dragStartY - dragUpdateY <= 100 &&
              dragStartY - dragUpdateY >= 0) {
            setState(() {
              yTransform = 0.0;
              opacity = yTransform / -400 * 0.8;
              rotation = yTransform / -400 * PI;
            });
          } else if (dragStartY - dragUpdateY <= -50) {
            setState(() {
              yTransform = 0.0;
              opacity = yTransform / -400 * 0.8;
              rotation = yTransform / -400 * PI;
            });
          }
        },
        child: Container(
          width: double.infinity,
          height: 500.0,
          child: Material(
            elevation: 20.0,
            color: Colors.grey[900],
            child: Column(
              children: <Widget>[
                //menu is here
              ],
            ),
          ),
        ),
      ),
    ),
  )
]),

What is also happening is that when I pull the menu up, I can't click any of the items in the new menu hitbox, I just seem to click through the menu on to the card below it.

like image 625
leodriesch Avatar asked May 26 '18 09:05

leodriesch


1 Answers

There a solution (workaround) to this but Unfortunately, this is the desired behavior.

I quote a Flutter maintainer from https://github.com/flutter/flutter/issues/6606:

We've decided this is working as it should. See: #6663

And then he closed the issue.

The problem

Basically, gesture detector does not detect any touch outside of original position before transform

The solution

The work around is to make the original widget big enough to cover the transform. We can add extra padding for that. For instance, if the transform widget moves the widget down by 100 px, just add padding bottom of 100 px to the original widget.

This will trick gesture detector to detect any touch inside the widget and the extra padding. So when the transform moves the widget, it will receive the touch events.

like image 121
TSR Avatar answered Sep 19 '22 21:09

TSR