Animated action menu built with Flutter. Includes effects like the rubber band effect, different gesture handling, and haptic feedback that come together for a great interactive feel.
๐ Original concept
action-menu.mov
The pull and stretch effect in the menu is similar to the sound & brightness sliders in the iOS control center.
The effect can be achieved by adjusting the scaling and positioning by the amount of stretch value, with a logarithmic function applied to it. With #Flutter this was done with a Transform.scale
widget that increases scaleY
, decreases scaleX
, and switches the alignment
between top and bottom based on the direction of the stretching.
๐ The standalone widget for this rubber band slider.
rubber-band-slider.mov
The overlay menu is achieved using an OverlayPortal
widget with a combination of CompositedTransformTarget
and CompositedTransformFollower
widgets to correctly position the overlay
![image](https://private-user-images.githubusercontent.com/50345358/328000993-fa9b3f34-addc-4f34-bbd0-9f27b9d75a9c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjUxMTE4MjYsIm5iZiI6MTcyNTExMTUyNiwicGF0aCI6Ii81MDM0NTM1OC8zMjgwMDA5OTMtZmE5YjNmMzQtYWRkYy00ZjM0LWJiZDAtOWYyN2I5ZDc1YTljLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MzElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODMxVDEzMzg0NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWIyYmVkMzExNzYyOWY4MGUxZDZkMTgyZTc3ZTk3YzdlNTAwYjJmNjFkZjE5NzgyY2FhY2JhNWVhZTdlNTRkODMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.vV41ZhRwi5UxZJQoahv9p-c9iBIo21KF_JTk_q2SYD8)
class _OverlayPortalSkeletonState extends State<OverlayPortalSkeleton> {
final _overlayController = OverlayPortalController();
final _link = LayerLink();
@override
Widget build(BuildContext context) {
return OverlayPortal(
controller: _overlayController,
overlayChildBuilder: (context) {
return CompositedTransformFollower(
link: _link,
targetAnchor: Alignment.topCenter,
followerAnchor: Alignment.bottomCenter,
child: const Align(
alignment: Alignment.bottomCenter,
child: ActionMenu(),
),
);
},
child: CompositedTransformTarget(
link: _link,
child: const ActionMenuButton(),
),
);
}
}
With different handling of gestures, using a Listener
and a GestureDetector
widget, both swapping up and long pressing on the action button open the overlay, with a spring effect on the long press gesture.
With those gestures, different levels of #HapticFeedback impacts are applied for an enhanced feel of responsiveness to user touch โจย (highly recommend you run it and experience it yourself!)
import 'package: flutter/services.dart';
// Very light vibration
HapticFeedback.lightImpact);
// Light vibration
HapticFeedback.mediumImpact);
// Medium vibration
HapticFeedback.heavyImpact);
// Long and high vibration
HapticFeedback.vibrate();
// Very short and light vibration
// Used to indicate UI changes, for example, in a Slider widget
HapticFeedback.selectionClick();