Robin Reiter
Robin Reiter

Reputation: 2537

onTapDown and other callbacks from GestureDetector() are delayed

I am currently using a GestureDetector() to create a custom button with an AnimatedContainer().

Goal is to get some sort of animation beeing scale, color, shadow or whatever once the user presses and releases the button.

My problem right now is that the onTapDown() callback is delayed. Maybe its because this button is actually an item within a SliverList which causes the delay. However if I tap on the GestureDetector without scrolling it takes a couple of hundred milliseconds until the onTapDown callback fires. Why?

I do understand that flutter and basically any other UI framework needs some sort of delayed touch for objects within a list. It has to determine of the user wants to scroll or press the button.

But do you have any ideas how I can display a nice scale animation once a user presses this container?

Here's the SliverList containing the RecipeMetaItem (which then reacts to touch input).

SliverList(
   delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
          MetaItem metaItem = state.metaItems[index];
          return RecipeMetaItem(metaItem: metaItem, height: 178);
      },
      childCount: state.metaItems.length,
   ),
)

And here is the portion of the RecipeMetaItem()


class RecipeMetaItem extends StatefulWidget {
  final double height;
  final MetaItem metaItem;

  const RecipeMetaItem({Key key, this.metaItem, this.height = 200}) : super(key: key);

  @override
  RecipeMetaItemState createState() {
    return new RecipeMetaItemState();
  }
}

class RecipeMetaItemState extends State<RecipeMetaItem> {
  double offset;


  @override
  void initState() {
    super.initState();
    offset = 0.0;
  }

  @override
  Widget build(BuildContext context) {

    return Padding(
      padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 20.0),
      child: GestureDetector(
        onTapDown: (details) {
          setState(() {
            offset = -10;
          });
        },
        onTapUp: (details) {
          setState(() {
            offset = 0;
          });
        },
        child: AnimatedContainer(
          duration: Duration(milliseconds: 60),
          curve: Curves.easeOut,
          transform: Matrix4.translationValues(0, offset, 0),
          child: Column(
            children: <Widget>[
              Container(
                height: widget.height,
                decoration: new BoxDecoration(
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withAlpha(40),
                      blurRadius: 12.5,
                      spreadRadius: 0.0,
                    )
                  ],
                  borderRadius: BorderRadius.all(Radius.circular(10)),
                ),
                child: ClipRRect(
                  borderRadius: BorderRadius.all(Radius.circular(10)),
                  child: Stack(
                    children: [
                      CachedNetworkImage(
                        fit: BoxFit.cover,
                        imageUrl: widget.metaItem.imageUrl,
                        fadeInDuration: Duration(milliseconds: 50),
                        errorWidget: (context, url, error) => new Icon(Icons.error),
                      ),
                    ],
                  ),
                ),
              ),
              Padding(
                padding: const EdgeInsets.only(top: 8.0, left: 4.0, right: 4.0),
                child: Row(
                  children: <Widget>[
                    Expanded(
                      child: Text(
                        widget.metaItem.title,
                        textAlign: TextAlign.left,
                        style: TextStyle(fontWeight: FontWeight.w700, fontSize: 17.0),
                      ),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Thanks!

Upvotes: 4

Views: 2479

Answers (1)

Tristan Bennett
Tristan Bennett

Reputation: 806

Not sure if you solved this one, but I found a similar question here on S.O. and I think the same solution might work for you!

Try switching the GestureDetector to a Listener and replacing the:

onTapDown: (details) {
  setState(() {
    offset = -10;
  });
},
onTapUp: (details) {
  setState(() {
    offset = 0;
  });
},

with:

onPointerDown: (PointerDownEvent event) {
  setState(() {
    offset = -10;
  });
},
onPointerUp: (PointerUpEvent event) {
  setState(() {
    offset = 0;
  });
},

Hopefully that solves it, in which case the issue would be the GestureDetector, not the child widget.

Upvotes: 5

Related Questions