Why isn't the image changing using the Provider Package?

Issue

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

Solution

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;

Answered By – Pieter van Loon

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *