liquid_glass_ui_kit 0.1.2
liquid_glass_ui_kit: ^0.1.2 copied to clipboard
An accessible, customizable Liquid Glass design system for Flutter with translucent themes and ready-made widgets for mobile, web, and desktop.
import 'package:flutter/cupertino.dart' show CupertinoIcons;
import 'package:flutter/material.dart';
import 'package:liquid_glass_ui_kit/liquid_glass_ui_kit.dart';
void main() => runApp(const DemoApp());
class DemoApp extends StatefulWidget {
const DemoApp({super.key});
@override
State<DemoApp> createState() => _DemoAppState();
}
class _DemoAppState extends State<DemoApp> {
bool _dark = true;
int _tab = 0;
bool _switchOn = true;
bool _animateIndicator = true;
bool _animateBounce = true;
bool _showLabels = true;
double _sliderValue = 0.53;
String _segment = 'for-you';
String _city = 'Jakarta';
static String _cityLabel(String city) => city;
void _openSheet(BuildContext context) {
showGlassBottomSheet(
context: context,
title: 'Share',
builder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Choose how you want to share this item.'),
const SizedBox(height: 20),
GlassButton(
label: 'Copy link',
icon: Icons.link_rounded,
variant: GlassButtonVariant.glass,
expand: true,
onPressed: () => Navigator.pop(context),
),
const SizedBox(height: 12),
GlassButton(
label: 'Done',
variant: GlassButtonVariant.filled,
expand: true,
onPressed: () => Navigator.pop(context),
),
],
),
);
}
void _openDialog(BuildContext context) {
showGlassDialog(
context: context,
title: 'Delete item?',
message: 'This action cannot be undone.',
actions: [
GlassDialogAction(
label: 'Cancel',
isDefault: true,
onPressed: () => Navigator.pop(context),
),
GlassDialogAction(
label: 'Delete',
isDestructive: true,
onPressed: () => Navigator.pop(context),
),
],
);
}
void _openMenu(BuildContext context) {
showGlassActionMenu(
context: context,
items: [
const GlassMenuItem(label: 'Edit', icon: Icons.edit_outlined),
const GlassMenuItem(label: 'Duplicate', icon: Icons.copy_rounded),
const GlassMenuItem(label: 'Share', icon: Icons.ios_share_rounded),
const GlassMenuItem(
label: 'Delete',
icon: Icons.delete_outline_rounded,
isDestructive: true,
),
],
);
}
static const _items = [
GlassNavItem(icon: Icons.home_rounded, label: 'Home'),
GlassNavItem(icon: Icons.sports_esports_rounded, label: 'Arcade'),
GlassNavItem(icon: Icons.group_rounded, label: 'Friends'),
GlassNavItem(icon: Icons.inventory_2_rounded, label: 'Library'),
GlassNavItem(icon: Icons.search_rounded, label: 'Search'),
];
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Liquid Glass UI',
home: GlassTheme(
data: _dark ? GlassThemeData.dark() : GlassThemeData.light(),
child: Builder(
builder: (context) {
final theme = GlassTheme.of(context);
return GlassScaffold(
// A colorful backdrop so the glass has something to refract.
background: const _Backdrop(),
appBar: const GlassAppBar(
title: Text('Liquid Glass'),
leading: Icon(Icons.arrow_back_ios_new_rounded, size: 20),
),
bottomNavigationBar: GlassBottomNavBar(
currentIndex: _tab,
onTap: (i) => setState(() => _tab = i),
items: _items,
animateIndicator: _animateIndicator,
animateBounce: _animateBounce,
showLabels: _showLabels,
),
body: ListView(
padding: const EdgeInsets.fromLTRB(16, 120, 16, 150),
children: [
const Wrap(
spacing: 8,
runSpacing: 8,
children: [
GlassPill(
label: 'Now Available',
icon: Icons.bolt_rounded,
),
GlassPill(label: 'iOS 26.4', selected: true),
GlassPill(label: 'Glassmorphism'),
],
),
const SizedBox(height: 20),
GlassCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Autocomplete + dropdown',
style: theme.typography.title3,
),
const SizedBox(height: 8),
Text(
'A macOS-style combo box accepts a suggested or '
'custom value.',
style: theme.typography.subheadline,
),
const SizedBox(height: 16),
GlassComboBox<String>(
label: 'Favorite City:',
placeholder: 'Enter a city',
helperText:
'Choose a suggestion or type another city.',
options: const [
'Jakarta',
'London',
'San Francisco',
'Singapore',
'Tokyo',
],
initialSelection: 'Jakarta',
displayStringForOption: _cityLabel,
onChanged: (value) => setState(() => _city = value),
onSelected: (value) => setState(() => _city = value),
),
const SizedBox(height: 12),
Text(
'Current value: $_city',
style: theme.typography.footnote,
),
],
),
),
const SizedBox(height: 20),
GlassCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Text fields', style: theme.typography.title3),
const SizedBox(height: 16),
GlassTextField(
label: 'Email',
placeholder: 'name@example.com',
prefix: const Icon(CupertinoIcons.mail),
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
autofillHints: const [AutofillHints.email],
),
const SizedBox(height: 16),
GlassTextField(
label: 'Password',
placeholder: 'Required',
prefix: const Icon(CupertinoIcons.lock),
obscureText: true,
autocorrect: false,
enableSuggestions: false,
autofillHints: const [AutofillHints.password],
),
],
),
),
const SizedBox(height: 20),
GlassCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Liquid controls', style: theme.typography.title3),
const SizedBox(height: 20),
LayoutBuilder(
builder: (context, constraints) => GlassSlider(
width: constraints.maxWidth,
value: _sliderValue,
activeColor: const Color(0xFF0A84FF),
semanticLabel: 'Playback position',
onChanged: (value) =>
setState(() => _sliderValue = value),
),
),
const SizedBox(height: 20),
LayoutBuilder(
builder: (context, constraints) =>
GlassSegmentedControl<String>(
width: constraints.maxWidth,
children: const {
'for-you': Text('For You'),
'library': Text('Library'),
},
selectedValue: _segment,
onValueChanged: (value) =>
setState(() => _segment = value),
),
),
],
),
),
const SizedBox(height: 20),
GlassCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Toggle settings', style: theme.typography.title3),
const SizedBox(height: 8),
Text(
'Each switch controls one clearly identified '
'on-or-off setting.',
style: theme.typography.subheadline,
),
const SizedBox(height: 16),
GlassToggleRow(
label: 'Dark appearance',
value: _dark,
onChanged: (v) => setState(() => _dark = v),
),
const SizedBox(height: 4),
GlassToggleRow(
label: 'Notifications',
description: 'Allow alerts about new activity.',
value: _switchOn,
onChanged: (v) => setState(() => _switchOn = v),
),
const SizedBox(height: 4),
GlassToggleRow(
label: 'Nav: slide indicator',
value: _animateIndicator,
onChanged: (v) =>
setState(() => _animateIndicator = v),
),
const SizedBox(height: 4),
GlassToggleRow(
label: 'Nav: bounce icon',
value: _animateBounce,
onChanged: (v) => setState(() => _animateBounce = v),
),
const SizedBox(height: 4),
GlassToggleRow(
label: 'Nav: show labels',
value: _showLabels,
onChanged: (v) => setState(() => _showLabels = v),
),
],
),
),
const SizedBox(height: 20),
GlassButton(
label: 'Filled action',
icon: Icons.arrow_forward_rounded,
variant: GlassButtonVariant.filled,
expand: true,
onPressed: () {},
),
const SizedBox(height: 12),
GlassButton(
label: 'Glass action',
variant: GlassButtonVariant.glass,
expand: true,
onPressed: () {},
),
const SizedBox(height: 12),
Center(
child: GlassButton(
label: 'Plain action',
variant: GlassButtonVariant.plain,
onPressed: () {},
),
),
const SizedBox(height: 24),
GlassButton(
label: 'Bottom sheet',
icon: Icons.vertical_align_bottom_rounded,
variant: GlassButtonVariant.glass,
expand: true,
onPressed: () => _openSheet(context),
),
const SizedBox(height: 12),
GlassButton(
label: 'Popup dialog',
icon: Icons.chat_bubble_outline_rounded,
variant: GlassButtonVariant.glass,
expand: true,
onPressed: () => _openDialog(context),
),
const SizedBox(height: 12),
Builder(
builder: (buttonContext) => GlassButton(
label: 'Action menu',
icon: Icons.more_horiz_rounded,
variant: GlassButtonVariant.glass,
expand: true,
onPressed: () => _openMenu(buttonContext),
),
),
],
),
);
},
),
),
);
}
}
/// A simple colorful gradient so the glass blur is visible.
class _Backdrop extends StatelessWidget {
const _Backdrop();
@override
Widget build(BuildContext context) {
return const DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF3A1C71),
Color(0xFFD76D77),
Color(0xFF2E8B8B),
],
),
),
);
}
}