1

I'm working with the Provider Package on Flutter but can't work out why it's not changing the background image when I call mymodel.image. It should access the MyModal class and change the existing image: Image.asset('images/background_image.jpeg', fit: BoxFit.fill) with the one in the SmallImage screen.

mymodel.image = Image.asset('images/hello_image.png', fit: BoxFit.fill);

Which replaces the background image on the HomePage.

HomePage Screen

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);
                  },
                ),
              ),
            ),
          ],
        ),
      );
    }
}

class MyModel extends ChangeNotifier {
  Image _image;
  set image(Image value) {
    _image = value;
    notifyListeners();
  }
  Image get image => _image;

}

SmallImage Screen

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:false); //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;
                                  });
                                  return mymodel.image  = Image.asset('images/hello_image.png', fit: BoxFit.fill);
                                  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'
                                  },
                                  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(),
                        ),
                      ],
                    );
                  }),
            ),
          ),
        );
  }
}
Ned Bayne-Powell
  • 181
  • 2
  • 16

1 Answers1

1

You have to call notifyListeners in your model when the image has changed otherwise the changenotifierprovider will not know that it needs to rebuild.

One way of doing the would be to wrap the image field with a getter and setter and call notifyListeners in the setter after updating the underlying field.

var Image _image;
set image(Image value) {
  _image = value;
  notifyListeners();
}
Image get image => _image;
Pieter van Loon
  • 5,318
  • 1
  • 6
  • 15
  • Thanks for the answer, I've called it inside here but it's still not working: class MyModel extends ChangeNotifier { Image image = Image.asset('images/background_image.jpeg', fit: BoxFit.fill); notifyListeners(); } – Ned Bayne-Powell Oct 24 '20 at 16:39
  • I cannot see the call to notifyListeners anywhere in the posted code. Can you update it to include it? – Pieter van Loon Oct 24 '20 at 16:46
  • Yes, I've added it in – Ned Bayne-Powell Oct 24 '20 at 16:47
  • Ok I think you don’t quite understand the code. You adden a method to your model that calls notifyListeners howeer that onChange method is still never called. When you set the new value to the image you need to call notifyListeners. One way of doing the would be to wrap the image field with a getter and setter and call notifyListeners in the setter after updating the underlying field. – Pieter van Loon Oct 24 '20 at 16:53
  • Hi Pieter, I've updated the code with your answer, would you be able to please have a look at it one last time as I'm still getting the image change? – Ned Bayne-Powell Oct 24 '20 at 17:19
  • In the Consumer you are also setting the image every build – Pieter van Loon Oct 24 '20 at 17:23
  • Would it be set image in the Consumer then? – Ned Bayne-Powell Oct 24 '20 at 18:01