quick_action_menu 1.0.0+1 copy "quick_action_menu: ^1.0.0+1" to clipboard
quick_action_menu: ^1.0.0+1 copied to clipboard

A Flutter package for displaying Telegram/WeChat-style context menus with smooth flying anchor animations, sticky menu behaviors, and backdrop blur effects.

Quick Action Menu #

pub package License: MIT Flutter

A Flutter package for displaying highly customizable context menus inspired by Telegram and WeChat-style quick action menus. Perfect for chat applications, message bubbles, or any widget that needs contextual actions with smooth "flying" anchor animations and sticky menu behaviors.

Demo for basic and scrollable content usage:

basic_demo scroll_demo

Table of Contents #


Features #

Feature Description
🎯 Contextual Menus Display customizable menus above and/or below any widget
Anchor Animation Smooth "fly-in" and "fly-out" animations for the anchor widget
📐 Smart Positioning Automatically calculates optimal menu position based on screen boundaries
↔️ Horizontal Alignment Control menu alignment relative to the anchor (left, center, right)
📌 Sticky Behavior Menus can stick to viewport edges during scrolling
🌫️ Background Effects Customizable overlay with color tint and backdrop blur
👆 Easy Dismissal Tap outside or dismiss programmatically
Performance Optimized Efficient layout with CustomMultiChildLayout
🔙 Back Button Support Automatically handles Android back button to dismiss menu

Installation #

Manual Installation #

Add quick_action_menu to your pubspec.yaml:

dependencies:
  quick_action_menu: ^1.0.0

Then run:

flutter pub get

CLI Installation #

Alternatively, run the following command in your terminal:

flutter pub add quick_action_menu

Quick Start #

1. Wrap with QuickActionMenu #

Wrap your widget tree with QuickActionMenu to enable the overlay system:

import 'package:flutter/material.dart';
import 'package:quick_action_menu/quick_action_menu.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: QuickActionMenu(
        child: const MyHomePage(),
      ),
    );
  }
}

2. Define an Anchor #

Wrap any widget with QuickActionAnchor and provide a unique tag:

QuickActionAnchor(
  tag: 'message_1',
  child: Container(
    padding: const EdgeInsets.all(16),
    decoration: BoxDecoration(
      color: Colors.blue,
      borderRadius: BorderRadius.circular(12),
    ),
    child: const Text(
      'Long press me!',
      style: TextStyle(color: Colors.white),
    ),
  ),
)

3. Show the Menu #

Call showMenu() on the QuickActionMenuState:

GestureDetector(
  onLongPress: () {
    QuickActionMenu.of(context).showMenu(
      tag: 'message_1',
      topMenuWidget: _buildReactionMenu(),
      bottomMenuWidget: _buildActionBar(),
    );
  },
  child: QuickActionAnchor(
    tag: 'message_1',
    child: const MessageBubble(),
  ),
)

API Reference #

QuickActionMenu #

The root widget that manages the overlay system. Place this high in your widget tree.

const QuickActionMenu({
  required Widget child,
  Key? key,
})
Property Type Description
child Widget Required. The widget tree containing anchor widgets

Static Methods

Method Returns Description
QuickActionMenu.of(context) QuickActionMenuState Retrieves the nearest QuickActionMenuState from the widget tree

QuickActionAnchor #

A widget that marks an anchor point for the quick action menu.

const QuickActionAnchor({
  required Object tag,
  Widget? child,
  QuickActionAnchorChildBuilder? childBuilder,
  QuickActionAnchorPlaceholderBuilder? placeholderBuilder,
  Key? key,
})
Property Type Description
tag Object Required. Unique identifier for this anchor
child Widget? The anchor widget (either child or childBuilder required)
childBuilder QuickActionAnchorChildBuilder? Builder for dynamic content based on extraction state
placeholderBuilder QuickActionAnchorPlaceholderBuilder? Builder for the placeholder shown when anchor is extracted

Type Definitions

/// Builder for placeholder widget
typedef QuickActionAnchorPlaceholderBuilder = Widget Function(
  BuildContext context,
  Size heroSize,
);

/// Builder for dynamic child based on extraction state
typedef QuickActionAnchorChildBuilder = Widget Function(
  BuildContext context,
  bool isExtracted,
  Widget? child,
);

QuickActionMenuState #

The state object that controls menu display. Access via QuickActionMenu.of(context).

Properties

Property Type Description
isMenuDisplayed bool Whether a menu is currently visible

Methods

showMenu()

Displays the quick action menu for the specified anchor.

void showMenu({
  required Object tag,
  Widget? topMenuWidget,
  Widget? bottomMenuWidget,
  OverlayMenuHorizontalAlignment topMenuAlignment,
  OverlayMenuHorizontalAlignment bottomMenuAlignment,
  Duration duration,
  Duration? reverseDuration,
  Curve overlayAnimationCurve,
  Curve anchorFlyAnimationCurve,
  Curve topMenuScaleCurve,
  Curve bottomMenuScaleCurve,
  Color overlayBackgroundColor,
  double overlayBackgroundOpacity,
  double backdropBlurSigmaX,
  double backdropBlurSigmaY,
  bool reverseScroll,
  EdgeInsets padding,
  StickyMenuBehavior stickyMenuBehavior,
})
Parameter Type Default Description
tag Object Required The unique tag of the target QuickActionAnchor
topMenuWidget Widget? null Widget displayed above the anchor
bottomMenuWidget Widget? null Widget displayed below the anchor
topMenuAlignment OverlayMenuHorizontalAlignment center Horizontal alignment of top menu
bottomMenuAlignment OverlayMenuHorizontalAlignment center Horizontal alignment of bottom menu
duration Duration Durations.short4 Animation duration
reverseDuration Duration? null Reverse animation duration (defaults to duration)
overlayAnimationCurve Curve Curves.easeOutCubic Curve for overlay fade/blur animations
anchorFlyAnimationCurve Curve Curves.easeOutSine Curve for anchor fly animation
topMenuScaleCurve Curve Curves.easeOutCubic Curve for top menu scale animation
bottomMenuScaleCurve Curve Curves.easeOutCubic Curve for bottom menu scale animation
overlayBackgroundColor Color Colors.black Background color of the overlay
overlayBackgroundOpacity double 0.2 Opacity of overlay background (0.0–1.0)
backdropBlurSigmaX double 10.0 Horizontal blur sigma
backdropBlurSigmaY double 10.0 Vertical blur sigma
reverseScroll bool false Reverse scroll direction (useful for chat UIs)
padding EdgeInsets EdgeInsets.zero Safe area padding for menu positioning
stickyMenuBehavior StickyMenuBehavior none Sticky behavior during scrolling
hideMenu()

Programmatically dismisses the currently displayed menu with animation.

Future<void> hideMenu()

Enums #

OverlayMenuHorizontalAlignment

Controls horizontal alignment of menu widgets relative to the anchor.

enum OverlayMenuHorizontalAlignment {
  left,    // Align menu to the left edge of anchor
  center,  // Center menu relative to anchor
  right,   // Align menu to the right edge of anchor
}

Defines how menus behave when the overlay content scrolls.

enum StickyMenuBehavior {
  none,    // Neither menu sticks
  top,     // Top menu sticks to viewport top during scroll
  bottom,  // Bottom menu sticks to viewport bottom during scroll
  both,    // Both menus stick to their respective edges
}

Advanced Usage #

Custom Placeholders #

Define what appears in place of the anchor when it "flies" to the overlay:

QuickActionAnchor(
  tag: 'message_1',
  placeholderBuilder: (context, size) {
    return Container(
      width: size.width,
      height: size.height,
      decoration: BoxDecoration(
        color: Colors.grey.withOpacity(0.3),
        borderRadius: BorderRadius.circular(12),
      ),
    );
  },
  child: const MessageBubble(),
)

Dynamic Child Builder #

React to the extraction state with childBuilder:

QuickActionAnchor(
  tag: 'message_1',
  childBuilder: (context, isExtracted, child) {
    return AnimatedOpacity(
      opacity: isExtracted ? 0.5 : 1.0,
      duration: const Duration(milliseconds: 200),
      child: child,
    );
  },
  child: const MessageBubble(),
)

Programmatic Control #

Check menu state and dismiss programmatically:

final menuState = QuickActionMenu.of(context);

// Check if menu is displayed
if (menuState.isMenuDisplayed) {
  // Dismiss with animation
  await menuState.hideMenu();
}

Example #

A complete example is available in the example directory.

import 'package:flutter/material.dart';
import 'package:quick_action_menu/quick_action_menu.dart';

class ChatScreen extends StatelessWidget {
  const ChatScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Chat')),
      body: QuickActionMenu(
        child: ListView.builder(
          itemCount: 20,
          itemBuilder: (context, index) {
            final tag = 'message_$index';
            return GestureDetector(
              onLongPress: () => _showMenu(context, tag),
              child: QuickActionAnchor(
                tag: tag,
                child: MessageBubble(index: index),
              ),
            );
          },
        ),
      ),
    );
  }

  void _showMenu(BuildContext context, String tag) {
    QuickActionMenu.of(context).showMenu(
      tag: tag,
      topMenuWidget: const ReactionPicker(),
      bottomMenuWidget: const ActionBar(),
      padding: MediaQuery.of(context).padding,
      stickyMenuBehavior: StickyMenuBehavior.top,
    );
  }
}

Contributing #

Contributions are welcome! Please feel free to:

  1. 🐛 Report bugs by opening an issue
  2. 💡 Suggest features or improvements
  3. 🔧 Submit pull requests

License #

This project is licensed under the MIT License - see the LICENSE file for details.

3
likes
150
points
64
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for displaying Telegram/WeChat-style context menus with smooth flying anchor animations, sticky menu behaviors, and backdrop blur effects.

Repository (GitHub)
View/report issues

Topics

#ui #menu #context-menu #overlay #animation

Documentation

API reference

License

MIT (license)

Dependencies

flutter, meta

More

Packages that depend on quick_action_menu