dynamic_glass_glmv 0.1.1
dynamic_glass_glmv: ^0.1.1 copied to clipboard
A Flutter package for reusable dynamic glass UI surfaces and adaptive platform bottom navigation.
example/lib/main.dart
import 'package:dynamic_glass_glmv/dynamic_glass_glmv.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() => runApp(const DynamicGlassExampleApp());
class DynamicGlassExampleApp extends StatelessWidget {
const DynamicGlassExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'dynamic_glass example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0xFF0A84FF),
),
home: const _HomeShell(),
);
}
}
class _HomeShell extends StatefulWidget {
const _HomeShell();
@override
State<_HomeShell> createState() => _HomeShellState();
}
class _HomeShellState extends State<_HomeShell> {
int _ordersBadge = 5;
@override
Widget build(BuildContext context) {
return DynamicGlassNavigationScaffold(
selectedItemColor: const Color(0xFF0A84FF),
minimizeBehavior: TabBarMinimizeBehavior.never,
split: true,
rightCount: 1,
onIndexChanged: (i) {
if (i == 1 && _ordersBadge > 0) {
// Clear the badge once the user opens Orders.
setState(() => _ordersBadge = 0);
}
},
items: [
AdaptiveNavigationDestination(
icon: SvgPicture.asset('assets/icons/box_outlined.svg'),
selectedIcon: SvgPicture.asset('assets/icons/box_filled.svg'),
label: 'Home',
),
AdaptiveNavigationDestination(
icon: SvgPicture.asset('assets/icons/profile.svg'),
label: 'Orders',
badgeCount: _ordersBadge > 0 ? _ordersBadge : null,
),
AdaptiveNavigationDestination(
icon: SvgPicture.asset('assets/icons/profile.svg'),
label: 'Profile',
),
const AdaptiveNavigationDestination(
icon: 'magnifyingglass',
label: 'Search',
isSearch: true,
hideLabel: true,
),
],
screens: const [
_ScrollingPage(
title: 'Home',
subtitle: 'Scroll to see the iOS 26 tab bar minimize.',
accent: Color(0xFF0A84FF),
),
_ScrollingPage(
title: 'Orders',
subtitle:
'Tapping this tab cleared the badge — re-run the app to see it again.',
accent: Color(0xFFFF9F0A),
),
_GlassShowcasePage(),
_SearchPage(),
],
);
}
}
/// A page with vertical scrolling content so the iOS 26 minimize-on-scroll
/// behavior has something to respond to.
class _ScrollingPage extends StatelessWidget {
const _ScrollingPage({
required this.title,
required this.subtitle,
required this.accent,
});
final String title;
final String subtitle;
final Color accent;
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverAppBar.large(
title: Text(title),
backgroundColor: accent.withValues(alpha: 0.15),
pinned: true,
),
SliverPadding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 120),
sliver: SliverList.builder(
itemCount: 40,
itemBuilder: (context, i) {
if (i == 0) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
subtitle,
style: Theme.of(context).textTheme.bodyLarge,
),
);
}
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: accent.withValues(alpha: 0.2),
child: Text('${i + 1}'),
),
title: Text('$title item ${i + 1}'),
subtitle: const Text('Tap me — or just scroll.'),
),
);
},
),
),
],
);
}
}
/// Minimal search surface — pairs with `isSearch: true` so the rightmost tab
/// renders as the detached `UISearchTab` pill on iOS 26.
class _SearchPage extends StatelessWidget {
const _SearchPage();
@override
Widget build(BuildContext context) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 24, 16, 120),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Search',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
const CupertinoSearchTextField(
placeholder: 'Type to search…',
),
const SizedBox(height: 24),
Text(
'On iOS 26 the rightmost tab is a UISearchTab, drawn as a detached '
'liquid-glass pill next to the main bar.',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
);
}
}
/// Demonstrates the DynamicGlass surface widget over a colorful background.
class _GlassShowcasePage extends StatelessWidget {
const _GlassShowcasePage();
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: [
const DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFFFF375F),
Color(0xFF0A84FF),
Color(0xFF30D158),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
Text(
'DynamicGlass surface',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
color: CupertinoColors.white,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 32),
DynamicGlass(
blur: 24,
opacity: 0.18,
borderRadius: BorderRadius.circular(24),
padding: const EdgeInsets.all(20),
child: const Text(
'Frosted glass over a gradient — pure Flutter.\n'
'On iOS 26 the bottom bar is real liquid glass.',
style: TextStyle(
color: CupertinoColors.white,
fontSize: 16,
height: 1.4,
),
),
),
],
),
),
),
],
);
}
}