Liqui
iOS-styled liquid sheets and buttons for Flutter with elegant spring animations.

Features
- Liquid Bottom Sheets: Smooth, spring-animated bottom sheets with iOS-style feel
- Popover Modals: Context menus and popovers anchored to source widgets
- Interactive Buttons: Circle buttons with liquid scale animations
- Spring Physics: Natural, elastic animations using spring simulation
- Responsive Design: Adaptive layouts for mobile and tablet
- Drag to Dismiss: Interactive dismissal with fluid feedback
Installation
Add to your pubspec.yaml:
dependencies:
liqui: ^0.2.1
Usage
Bottom Sheets
Show a liquid bottom sheet that slides from the bottom on mobile, or appears centered on tablets:
import 'package:liqui/liqui.dart';
showLiquiSheet(
context: context,
child: Container(
padding: EdgeInsets.all(20),
child: Text('Sheet Content'),
),
).whenComplete(() {
print('Sheet dismissed');
});
Popover Menus
Display a popover menu anchored to a button or widget:
showLiquiPopover(
context: context,
child: YourCustomWidget(),
);
Or override the anchor position manually:
showLiquiPopover(
context: context,
child: YourCustomWidget(),
position: Offset(100, 200), // Custom anchor position
);
Context Menus
Show a list of menu items with interactive highlighting:
showLiquiMenu(
context: context,
items: [
LiquiMenuItem(
title: 'Edit',
icon: Icons.edit,
onTap: () => print('Edit tapped'),
),
LiquiMenuItem(
title: 'Share',
icon: Icons.share,
onTap: () => print('Share tapped'),
),
LiquiMenuItem(
title: 'Delete',
icon: Icons.delete,
destructive: true,
onTap: () => print('Delete tapped'),
),
],
);
Menu Button
Create a button that opens a menu when tapped:
LiquiMenuButton(
items: [
LiquiMenuItem(
title: 'Option 1',
icon: Icons.star,
onTap: () => print('Option 1'),
),
LiquiMenuItem(
title: 'Option 2',
icon: Icons.favorite,
onTap: () => print('Option 2'),
),
],
builder: (context, showMenu) => GestureDetector(
onTap: showMenu,
child: Icon(Icons.more_horiz),
),
)
Circular Buttons
Beautiful circular buttons with liquid scale animations:
LiquiCircleButton(
icon: Icons.add,
onPressed: () => print('Button pressed'),
size: 32,
dark: false,
)
Create a group of circular buttons:
LiquiCircleButtonGroup(
buttons: [
LiquiCircleButton(icon: Icons.edit, onPressed: () {}),
LiquiCircleButton(icon: Icons.share, onPressed: () {}),
LiquiCircleButton(icon: Icons.delete, onPressed: () {}),
],
)
Close button:
LiquiCloseButton(
onPressed: () => Navigator.pop(context),
size: 32,
)
Scale Tap Animation
Add liquid scale animations to any widget:
LiquiScaleTap(
onPressed: () => print('Tapped'),
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20),
),
child: Center(child: Text('Tap Me')),
),
)
With custom scale and stretch settings:
LiquiScaleTap(
onPressed: () => print('Tapped'),
scaleOnPress: 1.2,
autoScaleBySize: false,
stretchSpringDamping: 10.0,
stretchSensitivity: 1.0,
translateSensitivity: 1.0,
child: YourWidget(),
)
Customization
Bottom Sheet Options
showLiquiSheet(
context: context,
child: YourWidget(),
backgroundColor: Colors.white,
barrierColor: Colors.black.withOpacity(0.5),
enableDrag: true,
width: 450,
borderRadius: 28,
useRootNavigator: false,
);
Popover Options
showLiquiPopover(
context: context,
child: YourWidget(),
backgroundColor: Colors.white,
barrierColor: Colors.transparent,
width: 300,
borderRadius: 20,
position: Offset(100, 200), // Optional: Custom anchor position
);
Menu Items
LiquiMenuItem(
title: 'Menu Item',
icon: Icons.star,
onTap: () => print('Tapped'),
destructive: false, // Red color for destructive actions
selected: false, // Show checkmark if selected
imageAsset: 'assets/icon.png', // Use image instead of icon
)
Button Customization
LiquiCircleButton(
icon: Icons.favorite,
onPressed: () {},
size: 40,
dark: true, // White icon on dark background
backgroundColor: Colors.blue,
)
Animation Configuration
The library uses spring physics for natural, elastic animations. You can customize the behavior through the BottomSheetConfig class constants or by adjusting widget parameters.
Scale Tap Parameters
scaleOnPress: Scale factor when pressed (default: 1.1)autoScaleBySize: Auto-calculate scale based on widget sizebasePixelIncrease: Pixel increase for auto-scale (default: 10.0)stretchSpringDamping: Damping for stretch animation (5.0-30.0)stretchSensitivity: Stretch responsiveness (0.5-2.0)translateSensitivity: Movement during drag (0.0-2.0)
Dependencies
elegant_spring_animation: ^2.0.2screen_corner_radius: ^3.0.0
Platform Support
- iOS
- Android
- Web
- macOS
- Windows
- Linux
License
This project is licensed under the MIT License.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Issues
If you encounter any issues or have suggestions, please file them in the issue tracker.