flutter_mesh_gradients 0.1.0
flutter_mesh_gradients: ^0.1.0 copied to clipboard
A Flutter package for creating beautiful, highly customizable fluid mesh gradients with custom shaders and static image export.
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_mesh_gradients/flutter_mesh_gradients.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Mesh Gradients Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MainScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _currentIndex = 0;
final List<Widget> _pages = [
const FullScreenDemo(),
const ComponentsDemo(),
const PalettesDemo(),
const StaticDemo(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _pages[_currentIndex],
bottomNavigationBar: NavigationBar(
selectedIndex: _currentIndex,
onDestinationSelected: (index) {
setState(() {
_currentIndex = index;
});
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.fullscreen),
label: 'Full Screen',
),
NavigationDestination(
icon: Icon(Icons.widgets),
label: 'Components',
),
NavigationDestination(
icon: Icon(Icons.palette),
label: 'Palettes',
),
NavigationDestination(
icon: Icon(Icons.image),
label: 'Static',
),
],
),
);
}
}
class FullScreenDemo extends StatefulWidget {
const FullScreenDemo({super.key});
@override
State<FullScreenDemo> createState() => _FullScreenDemoState();
}
class _FullScreenDemoState extends State<FullScreenDemo> {
double _amplitude = 0.2;
double _frequency = 0.5;
double _blur = 1.0;
double _speed = 1.0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
// Background Mesh Gradient
Positioned.fill(
child: FluidMeshGradient(
animate: true,
time: 15,
options: MeshGradientOptions(
speed: _speed,
amplitude: _amplitude,
frequency: _frequency,
blur: _blur,
color1: const Color(0xFF6A0DAD), // Deep Purple
color2: const Color(0xFFFF007F), // Neon Pink
color3: const Color(0xFF00E5FF), // Cyan
color4: const Color(0xFFFFD700), // Gold
),
),
),
// Overlay content
SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Fluid Mesh',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Colors.white,
letterSpacing: -1.0,
),
),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(30),
border: Border.all(
color: Colors.white.withValues(alpha: 0.3),
width: 1,
),
),
child: const Text(
'Stunning Animations',
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
),
],
),
),
),
// Controls
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.5),
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildSlider('Amplitude', _amplitude, 0.0, 1.0, (v) => setState(() => _amplitude = v)),
_buildSlider('Frequency', _frequency, 0.0, 10.0, (v) => setState(() => _frequency = v)),
_buildSlider('Blur', _blur, 0.1, 5.0, (v) => setState(() => _blur = v)),
_buildSlider('Speed', _speed, 0.0, 5.0, (v) => setState(() => _speed = v)),
],
),
),
],
),
),
],
);
}
Widget _buildSlider(String label, double value, double min, double max, ValueChanged<double> onChanged) {
return Row(
children: [
SizedBox(
width: 80,
child: Text(
label,
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
),
Expanded(
child: Slider(
value: value,
min: min,
max: max,
activeColor: Colors.white,
inactiveColor: Colors.white.withValues(alpha: 0.3),
onChanged: onChanged,
),
),
SizedBox(
width: 40,
child: Text(
value.toStringAsFixed(1),
style: const TextStyle(color: Colors.white),
),
),
],
);
}
}
class ComponentsDemo extends StatelessWidget {
const ComponentsDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Components'),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
const Text(
'Card Background',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
SizedBox(
height: 200,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Stack(
children: [
const Positioned.fill(
child: FluidMeshGradient(
options: MeshGradientOptions(
speed: 2.0,
color1: Color(0xFF00C9FF),
color2: Color(0xFF92FE9D),
color3: Color(0xFF00C9FF),
color4: Color(0xFF92FE9D),
),
),
),
Center(
child: Text(
'Beautiful Card',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w800,
color: Colors.white.withValues(alpha: 0.9),
shadows: [
Shadow(
color: Colors.black.withValues(alpha: 0.3),
blurRadius: 8,
),
],
),
),
),
],
),
),
),
const SizedBox(height: 32),
const Text(
'Button Background',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Center(
child: SizedBox(
width: 250,
height: 60,
child: ClipRRect(
borderRadius: BorderRadius.circular(30),
child: Stack(
children: [
const Positioned.fill(
child: FluidMeshGradient(
options: MeshGradientOptions(
speed: 3.0,
color1: Color(0xFFFF512F),
color2: Color(0xFFDD2476),
color3: Color(0xFFFF512F),
color4: Color(0xFFDD2476),
),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {},
splashColor: Colors.white.withValues(alpha: 0.3),
highlightColor: Colors.white.withValues(alpha: 0.1),
child: const Center(
child: Text(
'Tap Me!',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
),
),
),
),
],
),
);
}
}
class PalettesDemo extends StatelessWidget {
const PalettesDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Palettes & Speeds'),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildPaletteCard(
title: 'Sunset (Slow)',
speed: 0.5,
color1: const Color(0xFFFDC830),
color2: const Color(0xFFF37335),
color3: const Color(0xFFFDC830),
color4: const Color(0xFFF37335),
),
const SizedBox(height: 16),
_buildPaletteCard(
title: 'Ocean (Medium)',
speed: 1.5,
color1: const Color(0xFF2E3192),
color2: const Color(0xFF1BFFFF),
color3: const Color(0xFF2E3192),
color4: const Color(0xFF1BFFFF),
),
const SizedBox(height: 16),
_buildPaletteCard(
title: 'Neon (Fast)',
speed: 4.0,
color1: const Color(0xFFFF00FF),
color2: const Color(0xFF00FFFF),
color3: const Color(0xFFFF00FF),
color4: const Color(0xFF00FFFF),
),
],
),
);
}
Widget _buildPaletteCard({
required String title,
required double speed,
required Color color1,
required Color color2,
required Color color3,
required Color color4,
}) {
return SizedBox(
height: 150,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Positioned.fill(
child: FluidMeshGradient(
options: MeshGradientOptions(
speed: speed,
color1: color1,
color2: color2,
color3: color3,
color4: color4,
),
),
),
Positioned(
bottom: 16,
left: 16,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(20),
),
child: Text(
title,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
);
}
}
class StaticDemo extends StatefulWidget {
const StaticDemo({super.key});
@override
State<StaticDemo> createState() => _StaticDemoState();
}
class _StaticDemoState extends State<StaticDemo> {
Uint8List? _exportedBytes;
bool _isExporting = false;
Future<void> _exportImage() async {
setState(() => _isExporting = true);
try {
final bytes = await MeshGradientExporter.exportImageBytes(
size: const Size(300, 300),
options: const MeshGradientOptions(
color1: Color(0xFF6A0DAD),
color2: Color(0xFFFF007F),
color3: Color(0xFF00E5FF),
color4: Color(0xFFFFD700),
amplitude: 0.3,
frequency: 1.2,
speed: 1.0,
),
time: 5.0, // A fixed moment in time
);
setState(() => _exportedBytes = bytes);
} finally {
setState(() => _isExporting = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Static & Export')),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Static Mode (animate: false)',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Container(
width: 300,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(color: Colors.black26, blurRadius: 10, offset: Offset(0, 5))
],
),
clipBehavior: Clip.antiAlias,
child: const FluidMeshGradient(
animate: false,
time: 10,
options: MeshGradientOptions(
color1: Color(0xFF4CAF50),
color2: Color(0xFF8BC34A),
color3: Color(0xFFCDDC39),
color4: Color(0xFFFFEB3B),
),
),
),
const SizedBox(height: 32),
const Text(
'Export to Image',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: _isExporting ? null : _exportImage,
icon: _isExporting
? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
: const Icon(Icons.download),
label: const Text('Export Gradient'),
),
const SizedBox(height: 16),
if (_exportedBytes != null) ...[
const Text('Exported Result:'),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: Image.memory(
_exportedBytes!,
width: 150,
height: 150,
),
),
],
],
),
),
),
);
}
}