liquidify 0.1.1
liquidify: ^0.1.1 copied to clipboard
Seamless Liquid Glass extension for standard Flutter widgets. Transform standard Material & Cupertino widgets into Apple-style Liquid Glass with .liquidGlass().
Overview #
Liquidify brings Apple's authentic Liquid Glass design system to Flutter applications without the complexity of rewriting your interface or manually writing native platform code.
The Problem #
Achieving authentic Apple Liquid Glass in Flutter traditionally meant choosing between two frustrating extremes:
- Writing complex native code: Manually bridging iOS UIKit APIs (
UIGlassEffect,UIVisualEffectView,UITabBar,UINavigationBar) through custom Platform Views, Method Channels, and Xcode configuration. - Reinventing the wheel in Flutter: Replacing standard Flutter widgets with proprietary custom widgets, losing standard constructor parameters, keys, controllers, focus trees, accessibility semantics, and form validation in the process.
The Solution: One Simple Extension #
With Liquidify, you build your UI using standard Flutter widgets—exactly as you normally would—and simply append .liquidGlass():
BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
],
).liquidGlass();
Behind the scenes, Liquidify automatically handles everything:
- On iOS: Integrates native UIKit Platform Views using Apple's official
UIGlassEffect(iOS 26+) andUIVisualEffectViewfor real specular highlights, depth refraction, and authentic system materials. - On Android, Web, and Desktop: Automatically provides a smooth, GPU-accelerated backdrop blur fallback with specular gradients and multi-layered depth shadows.
- Everywhere: All callbacks (
onPressed,onChanged,onTap),TextEditingController,FocusNode, form validation, and semantics remain 100% intact.
Features #
- 18 Native iOS Platform Views: Directly embeds real iOS UIKit components utilizing Apple's official
UIGlassEffectandUIVisualEffectViewfor pixel-perfect specular refraction, fluid light response, and genuine system materials. - 32+ Supported Widgets: Buttons, inputs, navigation, containers, dialogs, pickers, progress indicators, and more — all via
.liquidGlass(). - Zero Rewrite Requirement: Extend standard widgets rather than replacing them with custom proprietary classes.
- Full State & Callback Preservation: Controllers, focus nodes, form keys, tap gestures, animations, and accessibility trees remain completely functional.
- Adaptive Cross-Platform Fallback: Seamlessly operates across Android, Web, macOS, Windows, and Linux using optimized shaders and backdrop filters.
- Forced Universal Mode: Enable
.liquidGlass(options: LiquidGlassOptions(force: true))to render the glass aesthetic uniformly across all operating systems. - Dynamic Lighting & Mode Adaptation: Automatic contrast adjustments for light mode (crystalline frost) and dark mode (translucent smoke).
- Extensible Architecture: Register custom widget adapters with
LiquidGlassRegistry.register<T>(). - Zero External Dart Dependencies: Lightweight, clean, and built on core Flutter and native UIKit APIs.
Installation #
Add liquidify to your project's pubspec.yaml:
flutter pub add liquidify
Import the package in your Dart code:
import 'package:liquidify/liquidify.dart';
Usage Examples #
Navigation Bar #
Scaffold(
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
onTap: (index) => setState(() => currentIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.widgets), label: 'Widgets'),
BottomNavigationBarItem(icon: Icon(Icons.palette), label: 'Themes'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
).liquidGlass(),
body: Center(child: Text('Active Index: $currentIndex')),
);
App Bar #
LiquidAppBar implements PreferredSizeWidget and directly slots into standard Scaffold.appBar:
Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
title: const Text('Liquidify'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _handleRefresh,
).liquidGlass(),
],
).liquidGlass(),
body: const ContentWidget(),
);
Form Controls & Sliders #
// Native UISlider on iOS, glass slider elsewhere
Slider(
value: sliderValue,
min: 0,
max: 100,
onChanged: (val) => setState(() => sliderValue = val),
).liquidGlass();
// Native UISwitch on iOS, glass toggle elsewhere
Switch(
value: isEnabled,
onChanged: (val) => setState(() => isEnabled = val),
).liquidGlass();
// Native UISegmentedControl on iOS
SegmentedButton<int>(
segments: const [
ButtonSegment(value: 0, label: Text('Frost')),
ButtonSegment(value: 1, label: Text('Crystal')),
ButtonSegment(value: 2, label: Text('Smoke')),
],
selected: {selectedSegment},
onSelectionChanged: (val) => setState(() => selectedSegment = val.first),
).liquidGlass();
Inputs & Text Fields #
TextField(
controller: searchController,
decoration: const InputDecoration(
hintText: 'Search components...',
prefixIcon: Icon(Icons.search),
),
onChanged: (query) => _filterResults(query),
).liquidGlass();
Buttons #
ElevatedButton(
onPressed: () => _handleSubmit(),
child: const Text('Confirm Action'),
).liquidGlass(
options: const LiquidGlassOptions(
tint: Color(0xFF007AFF),
),
);
Native iOS Platform Views #
Liquidify ships with 18 native UIKit Platform Views that render real Apple materials on iOS. These are used automatically by the adapter system, but you can also use them directly for maximum control.
Native Glass Container #
NativeLiquidGlassView(
width: 300,
height: 200,
cornerRadius: 20.0,
options: const LiquidGlassOptions(blur: 20),
child: const Center(child: Text('Hello Glass')),
fallback: const Card(child: Text('Non-iOS fallback')),
);
Native Glass Button #
NativeLiquidGlassButton(
title: 'Tap Me',
icon: 'star.fill', // SF Symbol name
cornerRadius: 12.0,
height: 48.0,
onPressed: () => print('Tapped!'),
fallback: ElevatedButton(
onPressed: () {},
child: const Text('Tap Me'),
),
);
Native Glass Tab Bar #
NativeLiquidGlassTabBar(
items: const [
NativeLiquidTabItem(icon: 'house.fill', label: 'Home'),
NativeLiquidTabItem(icon: 'magnifyingglass', label: 'Search'),
NativeLiquidTabItem(icon: 'gearshape.fill', label: 'Settings'),
],
selectedIndex: _currentIndex,
onTabSelected: (index) => setState(() => _currentIndex = index),
height: 80.0,
);
Native Glass Navigation Bar #
NativeLiquidGlassNavBar(
title: 'Settings',
height: 56.0,
fallback: AppBar(title: const Text('Settings')),
);
Native Glass Search Bar #
NativeLiquidGlassSearchBar(
placeholder: 'Search...',
onChanged: (text) => _filterResults(text),
onSubmitted: (text) => _performSearch(text),
height: 44.0,
);
Native Glass Text Field #
NativeLiquidGlassTextField(
placeholder: 'Enter your name',
text: _nameValue,
onChanged: (text) => setState(() => _nameValue = text),
height: 44.0,
);
Native Glass Switch #
NativeLiquidGlassSwitch(
value: _isEnabled,
onChanged: (val) => setState(() => _isEnabled = val),
height: 32.0,
);
Native Glass Slider #
NativeLiquidGlassSlider(
value: _sliderValue,
minimumValue: 0.0,
maximumValue: 100.0,
onChanged: (val) => setState(() => _sliderValue = val),
height: 32.0,
);
Native Glass Segmented Control #
NativeLiquidGlassSegmented(
segments: const ['Day', 'Week', 'Month'],
selectedIndex: _selectedSegment,
onChanged: (index) => setState(() => _selectedSegment = index),
height: 32.0,
);
Native Glass Alert Dialog #
NativeLiquidGlassAlert(
title: 'Delete Item?',
message: 'This action cannot be undone.',
actions: const [
NativeAlertAction(label: 'Cancel'),
NativeAlertAction(
label: 'Delete',
isDestructive: true,
isDefault: true,
),
],
onAction: (index) {
if (index == 1) _deleteItem();
},
height: 180.0,
);
Native Glass Bottom Sheet #
NativeLiquidGlassSheet(
cornerRadius: 20.0,
showHandle: true,
tintColor: Colors.blue.withValues(alpha: 0.1),
height: 300.0,
onDismiss: () => Navigator.pop(context),
);
Native Glass Date Picker #
// Date mode
NativeLiquidGlassDatePicker(
mode: LiquidDatePickerMode.date,
initialDate: DateTime.now(),
minimumDate: DateTime(2020),
maximumDate: DateTime(2030),
onChanged: (date) => setState(() => _selectedDate = date),
height: 340.0,
);
// Time mode
NativeLiquidGlassDatePicker(
mode: LiquidDatePickerMode.time,
onChanged: (time) => setState(() => _selectedTime = time),
height: 200.0,
);
// Date and Time combined
NativeLiquidGlassDatePicker(
mode: LiquidDatePickerMode.dateAndTime,
onChanged: (dateTime) => print('Selected: $dateTime'),
height: 340.0,
);
Native Glass Toolbar #
NativeLiquidGlassToolbar(
items: const [
NativeToolbarItem(icon: 'square.and.arrow.up', label: 'Share'),
NativeToolbarItem(icon: 'bookmark', label: 'Bookmark'),
NativeToolbarItem(icon: 'trash', label: 'Delete'),
],
tintColor: Colors.blue,
onItemTapped: (index) {
switch (index) {
case 0: _share();
case 1: _bookmark();
case 2: _delete();
}
},
height: 44.0,
);
Native Glass Context Menu #
NativeLiquidGlassMenu(
title: 'Options',
icon: 'ellipsis.circle',
items: const [
NativeMenuItem(label: 'Copy', icon: 'doc.on.doc'),
NativeMenuItem(label: 'Edit', icon: 'pencil'),
NativeMenuItem(
label: 'Delete',
icon: 'trash',
isDestructive: true,
),
],
onItemSelected: (index) {
switch (index) {
case 0: _copy();
case 1: _edit();
case 2: _delete();
}
},
height: 44.0,
);
Native Glass Progress Bar #
NativeLiquidGlassProgress(
progress: _downloadProgress, // 0.0 to 1.0
cornerRadius: 8.0,
trackHeight: 6.0,
tintColor: Colors.green,
height: 36.0,
);
Native Glass Activity Indicator #
// Simple spinner
NativeLiquidGlassActivity(
style: LiquidActivityStyle.medium,
cornerRadius: 16.0,
height: 48.0,
width: 48.0,
);
// Spinner with label
NativeLiquidGlassActivity(
style: LiquidActivityStyle.large,
label: 'Loading...',
color: Colors.blue,
cornerRadius: 20.0,
height: 56.0,
width: 160.0,
);
Native Glass Page Control #
NativeLiquidGlassPageControl(
numberOfPages: 5,
currentPage: _currentPage,
activeColor: Colors.blue,
inactiveColor: Colors.grey.withValues(alpha: 0.3),
onPageChanged: (page) => setState(() => _currentPage = page),
height: 36.0,
);
Native Glass Wheel Picker #
// Single column
NativeLiquidGlassPicker(
columns: const [
['Small', 'Medium', 'Large', 'Extra Large'],
],
initialSelections: const [1], // Start at "Medium"
onChanged: (change) {
print('Selected: ${change.value}');
},
height: 216.0,
);
// Multi-column (e.g. hours & minutes)
NativeLiquidGlassPicker(
columns: const [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
['00', '15', '30', '45'],
['AM', 'PM'],
],
initialSelections: const [7, 0, 0],
onChanged: (change) {
print('Column ${change.component}: ${change.value}');
},
height: 216.0,
);
Supported Widgets #
Adapter-Based Widgets (.liquidGlass() extension) #
| Category | Supported Widgets | iOS Native Platform View |
|---|---|---|
| Navigation | BottomNavigationBar, NavigationBar, TabBar, NavigationRail |
UITabBar, UINavigationBar |
| Containers | AppBar, SliverAppBar, Card, ListTile, Container |
UIGlassEffect / UIVisualEffectView |
| Inputs | TextField, TextFormField, SearchBar, DropdownButton |
UITextField, UISearchBar |
| Selection | Switch, Checkbox, Radio, SwitchListTile, CheckboxListTile, RadioListTile |
UISwitch |
| Sliders | Slider, RangeSlider |
UISlider |
| Buttons | ElevatedButton, FilledButton, OutlinedButton, TextButton, IconButton, FAB, SegmentedButton |
UIButton, UISegmentedControl |
| Dialogs | AlertDialog, Dialog |
Glass Modal |
| Chips & Progress | Chip, FilterChip, ActionChip, ChoiceChip, CircularProgressIndicator, LinearProgressIndicator |
Glass Material |
| Generic | Any standard Flutter Widget |
Universal Glass Wrapper |
Direct Native Platform Views (18 total) #
| Native Widget | UIKit Component | Description |
|---|---|---|
NativeLiquidGlassView |
UIVisualEffectView |
Generic glass container |
NativeLiquidGlassButton |
UIButton |
Tappable button with glass |
NativeLiquidGlassTabBar |
UITabBar |
Bottom tab navigation |
NativeLiquidGlassNavBar |
UINavigationBar |
Top navigation bar |
NativeLiquidGlassTextField |
UITextField |
Text input with glass |
NativeLiquidGlassSearchBar |
UISearchBar |
Search input |
NativeLiquidGlassSwitch |
UISwitch |
Toggle switch |
NativeLiquidGlassSlider |
UISlider |
Value slider |
NativeLiquidGlassSegmented |
UISegmentedControl |
Segmented selector |
NativeLiquidGlassAlert |
UIAlertController-style |
Alert dialog |
NativeLiquidGlassSheet |
UISheetPresentation-style |
Bottom sheet |
NativeLiquidGlassDatePicker |
UIDatePicker |
Date/time picker |
NativeLiquidGlassToolbar |
UIToolbar |
Action toolbar |
NativeLiquidGlassMenu |
UIMenu |
Context menu |
NativeLiquidGlassProgress |
UIProgressView |
Linear progress bar |
NativeLiquidGlassActivity |
UIActivityIndicatorView |
Loading spinner |
NativeLiquidGlassPageControl |
UIPageControl |
Page dots indicator |
NativeLiquidGlassPicker |
UIPickerView |
Wheel picker |
Customization with LiquidGlassOptions #
Fine-tune the glass material parameters per widget or apply them globally:
ElevatedButton(
onPressed: () {},
child: const Text('Customized'),
).liquidGlass(
options: const LiquidGlassOptions(
blur: 24.0, // Blur intensity radius
opacity: 0.80, // Glass material surface opacity
tint: Colors.blue, // Ambient tint overlay
borderWidth: 1.0, // Specular edge thickness
force: true, // Force glass on Android and Web
),
);
Built-in Presets #
// Subtle frosted texture (default)
LiquidGlassOptions.frosted()
// High-clarity crystalline refraction
LiquidGlassOptions.crystal()
// Deep translucent dark smoke
LiquidGlassOptions.smoke()
Global Theming #
Wrap your application tree in LiquidGlassTheme to set unified styling defaults:
LiquidGlassTheme(
options: const LiquidGlassOptions(
blur: 20.0,
opacity: 0.78,
),
child: MaterialApp(
home: const HomeScreen(),
),
);
Creating Custom Adapters #
Extend Liquidify to support your proprietary widgets:
class CustomCardAdapter extends LiquidGlassAdapter<CustomCard> {
const CustomCardAdapter();
@override
Widget build(CustomCard widget, LiquidGlassOptions options) {
return LiquidGlassContainer(
options: options,
child: widget.child,
);
}
}
// Register once during application startup:
LiquidGlassRegistry.register<CustomCard>(const CustomCardAdapter());
Architecture & Safety Guarantees #
- Non-Destructive: If an adapter encounters an unsupported widget or edge case, it safely returns the original widget unaltered.
- Platform-Respectful: iOS devices automatically receive genuine Apple UIKit materials. Non-Apple platforms automatically receive native Material/Cupertino representations unless
force: trueis explicitly passed. - Optimized Render Passes: Measured platform view embedding prevents layout thrashing and ensures smooth 120 FPS scrolling performance.
- Hybrid Architecture: The plugin uses a registry-based adapter system on the Dart side and factory-registered
FlutterPlatformViewclasses on the native side, enabling seamless hot-reload and widget-level native/fallback switching.
Platform Support #
| Platform | Rendering |
|---|---|
| iOS 26+ | Native UIGlassEffect via Platform Views |
| iOS < 26 | UIVisualEffectView with system blur fallback |
| Android | GPU-accelerated BackdropFilter with specular gradients |
| Web | CSS-backed blur with glass overlays |
| macOS | Native NSVisualEffectView (partial) |
| Windows/Linux | BackdropFilter fallback |
License #
This project is licensed under the MIT License. Developed by abdelhaliem.