iOS style button interaction animation implementation for Flutter A Flutter developer created TapButton, an iOS-style button interaction animation that replaces Flutter's default Material ripple effect with opacity-based press feedback. The widget uses Listener, RawGestureDetector, and FadeTransition to provide immediate opacity changes on pointer down and smooth recovery on release, while also supporting async taps, disabled states, loading states, and nested pointer blocking. | / | | | How to use TapButton | | | TapButton is a small iOS-style press effect wrapper that replaces Flutter's | | | default Material ripple. | | | It does not use: | | | - InkWell | | | - InkResponse | | | - Material splash / ripple | | | Instead, it uses: | | | - Listener | | | - RawGestureDetector | | | - FadeTransition | | | 1 Basic usage | | | dart | | | TapButton | | | onTap: { | | | print 'pressed' ; | | | }, | | | child: Container | | | height: 48, | | | padding: const EdgeInsets.symmetric horizontal: 20 , | | | decoration: BoxDecoration | | | color: Colors.black, | | | borderRadius: BorderRadius.circular 999 , | | | , | | | alignment: Alignment.center, | | | child: const Text | | | 'Continue', | | | style: TextStyle color: Colors.white , | | | , | | | , | | | | | | | | | 2 Async tap | | | asyncOnTap prevents duplicate taps while the async callback is running. | | | dart | | | TapButton | | | asyncOnTap: async { | | | await save ; | | | }, | | | child: const Text 'Save' , | | | | | | | | | 3 Disabled state | | | dart | | | TapButton | | | enabled: false, | | | onTap: {}, | | | child: const Text 'Disabled' , | | | | | | | | | 4 Loading state | | | When isLoading is true, taps are blocked and the opacity gently pulses. | | | dart | | | TapButton | | | isLoading: true, | | | onTap: {}, | | | child: const Text 'Loading' , | | | | | | | | | 5 Prevent parent TapButton from receiving a nested pointer | | | Use TapButtonPointerBlocker around children that should not trigger the | | | parent TapButton. | | | dart | | | TapButton | | | onTap: { | | | print 'parent' ; | | | }, | | | child: Row | | | children: | | | const Text 'Parent row' , | | | TapButtonPointerBlocker | | | child: Slider | | | value: 0.5, | | | onChanged: {}, | | | , | | | , | | | , | | | , | | | | | | | | | / | | | import 'dart:async'; | | | import 'package:flutter/gestures.dart'; | | | import 'package:flutter/material.dart'; | | | typedef AsyncTapCallback = FutureOr