I have wrapped the image field with a getter and setter and called notifyListeners in the setter after updating the underlying field but I can't work out how to set the image to every build.
return myModel.image = Image.asset('images/background_image.jpeg', fit: BoxFit.fill);
The background image get called and then on a different screen the user can tap on a small image which changes this background image to a different image
return myModel.image = Image.asset('images/iceland_background.jpg', fit: BoxFit.fill);
Main Screen with the background image:
import 'package:flutter/material.dart';
import 'package:flutter_app_background/small_images.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<MyModel>(
create: (context) => MyModel(),
child: MaterialApp(
title: 'Title',
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
title: Text('Background Image', style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold),
),
iconTheme: IconThemeData(color: Colors.white),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings, color: Colors.black,),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SmallImages()),
);
},
),
],
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Stack(
children: <Widget>
[
Positioned.fill(
child: GestureDetector(
child: Consumer<MyModel>(
builder: (context, myModel, child) {
return myModel.image = Image.asset('images/background_image.jpeg', fit: BoxFit.fill);
// return myValue;
},
),
),
),
],
),
);
}
}
class MyModel extends ChangeNotifier {
Image _image;
set image(Image value) {
_image = value;
notifyListeners();
}
Image get image => _image;
}
Other Screen with the small images that the user clicks on to change the background image:
import 'package:flutter/material.dart';
import 'package:flutter_app_background/main.dart';
import 'package:provider/provider.dart';
class SmallImages extends StatefulWidget {
static int tappedGestureDetector = 1;
@override
_SmallImagesState createState() => _SmallImagesState();
}
class _SmallImagesState extends State<SmallImages> {
List<bool> isSelected;
void initState() {
isSelected = [true, false, false, false, false, false, false, false, false];
super.initState();
}
@override
Widget build(BuildContext context) {
final myModel = Provider.of<MyModel>(context,listen:true); //default for listen is `true`
return Scaffold(
appBar: AppBar(
title: Text('Small Image', style: TextStyle(
color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold),
),
iconTheme: IconThemeData(color: Colors.white),
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_left, color: Colors.black,),
onPressed: () {
Navigator.pop(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
},
),
],
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Material(
child: GestureDetector(
child: MaterialApp(
builder: (context, snapshot) {
return GridView.count(
crossAxisCount: 1,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
children: [
GridView(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3,
childAspectRatio: MediaQuery
.of(context)
.size
.width /
(MediaQuery
.of(context)
.size
.height / 2),
),
children: [
GestureDetector(
onTap: () {
// return myValue;
setState(() {
SmallImages.tappedGestureDetector = 1;
});
print('hi');
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 1
? Border.all(
color: Color(0xff2244C7), width: 1.0)
: Border
.all(color: Colors.transparent,),),
child: Image.asset(
'images/nightsky_image.png',
),
),
),
Consumer<MyModel>(
builder: (context, myModel, child) {
return GestureDetector(
onTap: () {
setState(() {
SmallImages.tappedGestureDetector = 2;
}); // <-- replaced 'tapped' and 'other'
return myModel.image = Image.asset('images/iceland_background.jpg', fit: BoxFit.fill);
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 2
? Border.all(
color: Color(0xff2244C7), width: 1.0)
: Border
.all(color: Colors.transparent,),),
child: Image.asset(
'images/own_image.png',
),
),
);
},
),
Consumer<MyModel>(
builder: (context, myModel, child) {
return GestureDetector(
onTap: () {
setState(() {
SmallImages.tappedGestureDetector = 3;
}); // <-- replaced 'tapped' and 'other'
},
child: Container(
height: 100,
width: 107,
decoration: BoxDecoration(border: SmallImages
.tappedGestureDetector == 3
? Border.all(
color: Color(0xff2244C7), width: 1.0)
: Border
.all(color: Colors.transparent,),),
child: Image.asset(
'images/iceland_image.png',
),
),
);
},
),
].toList(),
),
],
);
}),
),
),
);
}
}
To make the
images/background_image.jpeg
be the image that is used if no other image is selected you should changereturn myModel.image = Image.asset('images/background_image.jpeg', fit: BoxFit.fill);
toreturn myModel.image ?? Image.asset('images/background_image.jpeg', fit: BoxFit.fill);
What the
??
does here is it checks ifmyModel.image
is null, if it is null than it uses the fallback background image and if it is not null it will usemyModel.image
as the image.Btw in the onTap you don’t need the return so change that to
myModel.image = Image.asset('images/iceland_background.jpg', fit: BoxFit.fill);