liquid_glass_renderer 0.1.1-dev.2
liquid_glass_renderer: ^0.1.1-dev.2 copied to clipboard
The raw renderer for a liquid glass effect in Flutter.
example/lib/main.dart
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:liquid_glass_renderer/liquid_glass_renderer.dart';
import 'package:rivership/rivership.dart';
import 'package:smooth_sheets/smooth_sheets.dart';
void main() {
runApp(const MainApp());
}
final thicknessNotifier = ValueNotifier<double>(20);
final blurFactorNotifier = ValueNotifier<double>(.02);
final cornerRadiusNotifier = ValueNotifier<double>(100);
final glassColorNotifier = ValueNotifier<Color>(
const Color.fromARGB(0, 255, 255, 255),
);
final lightIntensityNotifier = ValueNotifier<double>(5);
final blendNotifier = ValueNotifier<double>(50);
final chromaticAberrationNotifier = ValueNotifier<double>(1);
class MainApp extends HookWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
final thicknessVisible = useState(true);
final blend = useValueListenable(blendNotifier);
final chromaticAberration = useValueListenable(chromaticAberrationNotifier);
final spring = Spring.bouncy.copyWith(durationSeconds: .8, bounce: 0.3);
final thickness = useSingleMotion(
value: thicknessVisible.value ? thicknessNotifier.value : 0,
motion: SpringMotion(spring),
);
final blur = thickness * blurFactorNotifier.value;
final lightAngleController = useAnimationController(
duration: const Duration(seconds: 5),
lowerBound: 0,
upperBound: 2 * pi,
)..repeat();
final lightAngle = useAnimation(lightAngleController);
final cornerRadius = useSingleMotion(
value: cornerRadiusNotifier.value,
motion: SpringMotion(spring.copyWithDamping(durationSeconds: 1.2)),
);
final color = useTweenAnimation(
ColorTween(
begin: glassColorNotifier.value,
end: glassColorNotifier.value,
),
)!;
final colorScheme = ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: Color(0xFF287390),
);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.from(
colorScheme: colorScheme,
textTheme: GoogleFonts.lexendDecaTextTheme().apply(
displayColor: colorScheme.onSurface,
bodyColor: colorScheme.onSurface,
),
),
home: Scaffold(
body: Builder(
builder: (context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
ModalSheetRoute(
barrierColor: Colors.black26,
swipeDismissible: true,
viewportPadding: const EdgeInsets.all(100),
builder: (context) {
return SettingsSheet();
},
),
);
},
child: Background(
child: LiquidGlassLayer(
settings: LiquidGlassSettings(
thickness: thickness,
lightAngle: lightAngle,
glassColor: color.withValues(
alpha: color.a * thickness / 20,
),
lightIntensity: lightIntensityNotifier.value,
ambientStrength: 0.8,
outlineIntensity: 2,
blend: blend,
chromaticAberration: chromaticAberration,
),
child: Stack(
alignment: Alignment.bottomLeft,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 90, left: 140),
child: DragDismissable(
threshold: double.maxFinite,
velocityThreshold: double.maxFinite,
spring: Spring.bouncy,
child: LiquidGlass.inLayer(
blur: blur,
shape: LiquidRoundedSuperellipse(
borderRadius: Radius.circular(cornerRadius),
),
child: Container(
color: Colors.transparent,
child: SizedBox.square(dimension: 160),
),
),
),
),
Align(
alignment: Alignment.topRight,
child: DragDismissable(
threshold: double.maxFinite,
velocityThreshold: double.maxFinite,
spring: Spring.bouncy,
child: LiquidGlass.inLayer(
glassContainsChild: false,
blur: blur,
shape: LiquidRoundedSuperellipse(
borderRadius: Radius.circular(cornerRadius),
),
child: Padding(
padding: const EdgeInsets.all(64.0),
child: FlutterLogo(size: 200),
),
),
),
),
Align(
alignment: Alignment.topLeft,
child: DragDismissable(
threshold: double.maxFinite,
velocityThreshold: double.maxFinite,
spring: Spring.bouncy,
child: LiquidGlass.inLayer(
glassContainsChild: false,
blur: blur,
shape: LiquidOval(),
child: Container(
width: 100,
height: 80,
color: Colors.transparent,
),
),
),
),
],
),
),
),
);
},
),
),
);
}
}
class Background extends HookWidget {
const Background({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context) {
final showHint = useDelayed(
delay: Duration(seconds: 1),
before: false,
after: true,
);
useEffect(() {
if (showHint) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Drag Glass or tap anywhere!",
style: GoogleFonts.lexendDecaTextTheme().bodyLarge!.copyWith(
color: Theme.of(context).colorScheme.onInverseSurface,
),
),
),
);
});
}
return null;
}, [showHint]);
return SizedBox.expand(
child: Container(
color: Theme.of(context).colorScheme.surface,
child: Container(
margin: const EdgeInsets.only(bottom: 64, left: 64),
decoration: ShapeDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHighest,
shape: RoundedSuperellipseBorder(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(80)),
),
),
child: Container(
margin: const EdgeInsets.only(bottom: 16, left: 16),
decoration: ShapeDecoration(
image: DecorationImage(
image: AssetImage('assets/wallpaper.webp'),
fit: BoxFit.cover,
),
shape: RoundedSuperellipseBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(64),
),
),
),
child: Padding(
padding: const EdgeInsets.all(64.0),
child: Stack(
fit: StackFit.expand,
children: [
Align(
alignment: Alignment.bottomLeft,
child: Text(
'Liquid\nGlass\nRenderer',
style: GoogleFonts.lexendDecaTextTheme().headlineLarge
?.copyWith(
fontSize: 120,
height: 1,
fontWeight: FontWeight.w900,
color: Color(0xFF287390),
),
),
),
child,
],
),
),
),
),
),
);
}
}
class SettingsSheet extends StatelessWidget {
const SettingsSheet({super.key});
@override
Widget build(BuildContext context) {
return Sheet(
dragConfiguration: SheetDragConfiguration(),
scrollConfiguration: const SheetScrollConfiguration(),
initialOffset: SheetOffset(1),
shrinkChildToAvoidDynamicOverlap: true,
shrinkChildToAvoidStaticOverlap: true,
snapGrid: SheetSnapGrid(snaps: [SheetOffset(0.5), SheetOffset(1)]),
child: SafeArea(
child: LiquidGlass(
blur: 10,
glassContainsChild: false,
settings: LiquidGlassSettings(
thickness: 40,
lightIntensity: .4,
ambientStrength: 2,
chromaticAberration: 4,
glassColor: Theme.of(
context,
).colorScheme.surface.withValues(alpha: 0.4),
),
shape: LiquidRoundedSuperellipse(borderRadius: Radius.circular(24)),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.bodyLarge!,
child: Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Settings',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
Text('Thickness:'),
CupertinoSlider(
value: thicknessNotifier.value,
onChanged: (value) {
thicknessNotifier.value = value;
},
min: 0,
max: 100,
),
Text('Corner Radius:'),
CupertinoSlider(
value: cornerRadiusNotifier.value,
onChanged: (value) {
cornerRadiusNotifier.value = value;
},
min: 0,
max: 100,
),
Text('Light Intensity:'),
CupertinoSlider(
value: lightIntensityNotifier.value,
onChanged: (value) {
lightIntensityNotifier.value = value;
},
min: 0,
max: 5,
),
Text('Blur:'),
CupertinoSlider(
value: blurFactorNotifier.value,
onChanged: (value) {
blurFactorNotifier.value = value;
},
),
Text('Liquid Factor™:'),
CupertinoSlider(
value: blendNotifier.value,
onChanged: (value) {
blendNotifier.value = value;
},
min: 0,
max: 100,
),
Text('Chromatic Aberration:'),
CupertinoSlider(
value: chromaticAberrationNotifier.value,
onChanged: (value) {
chromaticAberrationNotifier.value = value;
},
min: 0,
max: 10,
),
],
),
),
),
),
),
),
),
);
}
}