Created
December 16, 2023 23:46
-
-
Save Rahiche/93d5df0a13b9894b47a49064364ce36f to your computer and use it in GitHub Desktop.
Gradual blur cards using ImageFilter.compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:ui'; | |
import 'package:flutter/material.dart'; | |
void main() => runApp(const MyApp()); | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
theme: ThemeData.dark(), | |
home: MyHomePage(), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
const MyHomePage({super.key}); | |
@override | |
State<MyHomePage> createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
List<DataModel> dummyDataList = [ | |
DataModel( | |
title: 'Modern Artistic Living Room', | |
desc: | |
'A white contemporary sofa adorned with earth-toned cushions, bold abstract wall art, a sleek black marble fireplace, and an eclectic collection of sculptural pieces in a sophisticated living space.', | |
url: 'https://i.imgur.com/sHuAqc7.png'), | |
DataModel( | |
title: 'Elegant Gift Tower', | |
desc: | |
'A stack of glittering gold and deep red gift boxes tied with satin ribbons against a soft glowing light backdrop, symbolizing luxury and festivity.', | |
url: 'https://i.imgur.com/u8KRGK2.png'), | |
DataModel( | |
title: 'Assorted Tartlets Platter', | |
desc: | |
'A delectable assortment of tartlets with flaky crusts, topped with chocolate ganache, fresh berries, and powdered sugar, offering a tempting variety of flavors.', | |
url: 'https://i.imgur.com/SohsdwI.png'), | |
DataModel( | |
title: 'Citrus Symphony', | |
desc: | |
'An up-close display of citrus slices with water droplets, showcasing the fresh pulp and vibrant colors of limes, oranges, and lemons arranged in a pleasing pattern.', | |
url: 'https://i.imgur.com/REutjjm.png') | |
]; | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Smooth Edge'), | |
), | |
body: GridView.builder( | |
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( | |
// Use a ternary operator to determine the cross axis count based on the screen width | |
crossAxisCount: MediaQuery.of(context).size.width > 600 ? 3 : 2, | |
crossAxisSpacing: 10, // Space between columns | |
mainAxisSpacing: 10, // Space between rows | |
childAspectRatio: 1.7, | |
), | |
itemCount: dummyDataList.length, | |
itemBuilder: (context, index) { | |
final item = dummyDataList[index]; | |
return AppCard(dataModel: item); | |
}, | |
), | |
); | |
} | |
} | |
class DataModel { | |
final String title; | |
final String desc; | |
final String url; | |
DataModel({required this.title, required this.desc, required this.url}); | |
} | |
class AppCard extends StatefulWidget { | |
const AppCard({ | |
Key? key, | |
required this.dataModel, | |
}) : super(key: key); | |
final DataModel dataModel; | |
@override | |
State<AppCard> createState() => _AppCardState(); | |
} | |
class _AppCardState extends State<AppCard> { | |
bool isHovering = false; | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: MouseRegion( | |
onEnter: (event) => setState(() => isHovering = true), | |
onExit: (event) => setState(() => isHovering = false), | |
child: Card( | |
color: Colors.transparent, | |
clipBehavior: Clip.antiAlias, | |
child: Stack( | |
alignment: Alignment.center, | |
children: <Widget>[ | |
Positioned.fill( | |
child: Image.network( | |
widget.dataModel.url, | |
width: double.infinity, | |
height: 250.0, | |
fit: BoxFit.cover, | |
), | |
), | |
if (isHovering) // Show blur only on hover | |
Positioned( | |
bottom: -25, | |
left: 0, | |
right: 0, | |
child: ImageFiltered( | |
imageFilter: ImageFilter.compose( | |
outer: ImageFilter.blur( | |
sigmaY: 20, | |
sigmaX: 20, | |
tileMode: TileMode.decal, | |
), | |
inner: ImageFilter.blur( | |
sigmaX: 20 + 20, | |
sigmaY: 10 + 20, | |
tileMode: TileMode.clamp, | |
), | |
), | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: ClipRect( | |
child: Align( | |
alignment: Alignment.bottomCenter, | |
heightFactor: 0.2, | |
child: Image.network( | |
widget.dataModel.url, | |
height: 250.0, | |
width: double.infinity, | |
fit: BoxFit.cover, | |
), | |
), | |
), | |
), | |
), | |
), | |
Positioned( | |
bottom: 8, | |
left: 8, | |
right: 8, | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: [ | |
Text( | |
widget.dataModel.title, | |
style: const TextStyle( | |
fontSize: 20, | |
fontWeight: FontWeight.bold, | |
color: Colors.white), | |
), | |
Text( | |
widget.dataModel.desc, | |
style: const TextStyle(color: Colors.white), | |
), | |
], | |
), | |
) | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment