Created
September 25, 2025 11:41
-
-
Save softmarshmallow/60dac1c6fea7f9809f9bc48127523bf4 to your computer and use it in GitHub Desktop.
demo for demonstrating flutter's image fit & repeat, scaling capability and modeling.
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 'package:flutter/material.dart'; | |
| import 'package:provider/provider.dart'; | |
| void main() => runApp(const MyApp()); | |
| /// Data model for managing the image display settings. | |
| class ImageDisplaySettings extends ChangeNotifier { | |
| static const String _imageUrl = | |
| 'https://www.gstatic.com/flutter-onestack-prototype/genui/example_1.jpg'; | |
| BoxFit _boxFit; | |
| ImageRepeat _imageRepeat; | |
| double _imageScale; | |
| ImageDisplaySettings() | |
| : _boxFit = BoxFit.cover, | |
| _imageRepeat = ImageRepeat.noRepeat, | |
| _imageScale = 1.0; | |
| String get imageUrl => _imageUrl; | |
| BoxFit get boxFit => _boxFit; | |
| ImageRepeat get imageRepeat => _imageRepeat; | |
| double get imageScale => _imageScale; | |
| void setBoxFit(BoxFit newBoxFit) { | |
| if (_boxFit != newBoxFit) { | |
| _boxFit = newBoxFit; | |
| notifyListeners(); | |
| } | |
| } | |
| void setImageRepeat(ImageRepeat newImageRepeat) { | |
| if (_imageRepeat != newImageRepeat) { | |
| _imageRepeat = newImageRepeat; | |
| notifyListeners(); | |
| } | |
| } | |
| void setImageScale(double newImageScale) { | |
| if (_imageScale != newImageScale) { | |
| _imageScale = newImageScale; | |
| notifyListeners(); | |
| } | |
| } | |
| } | |
| class MyApp extends StatelessWidget { | |
| const MyApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return ChangeNotifierProvider<ImageDisplaySettings>( | |
| create: (BuildContext context) => ImageDisplaySettings(), | |
| builder: (BuildContext context, Widget? child) { | |
| return MaterialApp( | |
| title: 'Decoration Image Showcase', | |
| debugShowCheckedModeBanner: false, | |
| theme: ThemeData(colorSchemeSeed: Colors.blue), | |
| home: const DecorationImageDemoPage(), | |
| ); | |
| }, | |
| ); | |
| } | |
| } | |
| class DecorationImageDemoPage extends StatelessWidget { | |
| const DecorationImageDemoPage({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| final ImageDisplaySettings settings = | |
| Provider.of<ImageDisplaySettings>(context); | |
| return Scaffold( | |
| appBar: AppBar( | |
| title: const Text('Decoration Image Showcase'), | |
| ), | |
| body: ListView( | |
| padding: const EdgeInsets.all(16.0), | |
| children: <Widget>[ | |
| const Text( | |
| 'Interactive Image Display', | |
| style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold), | |
| ), | |
| const SizedBox(height: 16), | |
| Center( | |
| child: Container( | |
| width: 300, | |
| height: 200, | |
| decoration: BoxDecoration( | |
| color: Colors.grey[200], // Background color in case image is loading or fails | |
| borderRadius: BorderRadius.circular(16.0), | |
| boxShadow: const <BoxShadow>[ | |
| BoxShadow( | |
| color: Colors.black26, | |
| blurRadius: 8.0, | |
| offset: Offset(0, 4), | |
| ), | |
| ], | |
| image: DecorationImage( | |
| image: NetworkImage(settings.imageUrl), | |
| fit: settings.boxFit, | |
| alignment: Alignment.center, | |
| repeat: settings.imageRepeat, | |
| scale: settings.imageScale, | |
| ), | |
| ), | |
| child: const Center( | |
| child: Text( | |
| 'Featured Image', | |
| style: TextStyle( | |
| color: Colors.white, | |
| fontSize: 24, | |
| fontWeight: FontWeight.bold, | |
| shadows: <Shadow>[ | |
| Shadow( | |
| offset: Offset(1.0, 1.0), | |
| blurRadius: 3.0, | |
| color: Color.fromARGB(150, 0, 0, 0), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| const SizedBox(height: 24), | |
| const Text( | |
| 'Image Properties:', | |
| style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), | |
| ), | |
| const SizedBox(height: 12), | |
| ListTile( | |
| title: const Text('BoxFit Mode'), | |
| trailing: DropdownButton<BoxFit>( | |
| value: settings.boxFit, | |
| onChanged: (BoxFit? newValue) { | |
| if (newValue != null) { | |
| settings.setBoxFit(newValue); | |
| } | |
| }, | |
| items: BoxFit.values.map<DropdownMenuItem<BoxFit>>( | |
| (BoxFit value) { | |
| return DropdownMenuItem<BoxFit>( | |
| value: value, | |
| child: Text(value.toString().split('.').last), | |
| ); | |
| }, | |
| ).toList(), | |
| ), | |
| ), | |
| ListTile( | |
| title: const Text('ImageRepeat Mode'), | |
| trailing: DropdownButton<ImageRepeat>( | |
| value: settings.imageRepeat, | |
| onChanged: (ImageRepeat? newValue) { | |
| if (newValue != null) { | |
| settings.setImageRepeat(newValue); | |
| } | |
| }, | |
| items: ImageRepeat.values.map<DropdownMenuItem<ImageRepeat>>( | |
| (ImageRepeat value) { | |
| return DropdownMenuItem<ImageRepeat>( | |
| value: value, | |
| child: Text(value.toString().split('.').last), | |
| ); | |
| }, | |
| ).toList(), | |
| ), | |
| ), | |
| ListTile( | |
| title: Text('Image Scale: ${settings.imageScale.toStringAsFixed(1)}x'), | |
| trailing: SizedBox( | |
| width: 200, // Constrain slider width | |
| child: Slider( | |
| value: settings.imageScale, | |
| min: 0.1, | |
| max: 5.0, | |
| divisions: 49, // 0.1 increments | |
| label: settings.imageScale.toStringAsFixed(1), | |
| onChanged: (double newValue) { | |
| settings.setImageScale(newValue); | |
| }, | |
| ), | |
| ), | |
| ), | |
| ], | |
| ), | |
| ); | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://dartpad.dev/?id=60dac1c6fea7f9809f9bc48127523bf4
This demo show cases, how each property of DecorationImage actually produces lots of no-op, that this is not the best model how we would design Image model