fluttertabviewscoped-model

Scoped Model initialized when Key Board is popped up for TextField


I have two tabs with a Default Tab bar. I have used Scoped-model for passing data between two tabs. When I insert data in one tab and press text Field again so that keyboard pops up but whole model gets reinitialized.

I have tried AutomaticKeepAliveClientMixin but no result. I have found out that every time I press the Text Field, keyBoard pops up and the Scoped model gets initialized. I have checked that by printing string in Scoped-Model constructor.

Here is my TabView

import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/FirstScreen.dart';
import 'package:basicflutter/tabs/SecondScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';

class MyTabs extends StatelessWidget {
  static String tag = 'tab-page';
  @override


  Widget build(BuildContext context) {
    return ScopedModel<ProductsModel>(
  model: ProductsModel(),
  child: MaterialApp(
    home: DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(icon: Icon(Icons.directions_car)),
              Tab(icon: Icon(Icons.directions_transit)),
            ],
          ),
          title: Text('Flutter Tabs Example'),
        ),
        body: TabBarView(
          children: [
            FirstScreen(),
            SecondScreen(),
            ],
          ),
        ),
      ),
    ),
   );
  }
}

Here is my FirstScreen which takes Name and Image as input and then inserts them in an ArrayList

    import 'package:flutter/material.dart';
    import 'package:image_picker/image_picker.dart';
    import 'dart:io';
    import 'package:flutter/material.dart';
    import 'package:basicflutter/tabs/SecondScreen.dart';
    import 'package:basicflutter/models/product.dart';
    import 'package:basicflutter/scopedModel/addproduct.dart';
    import 'package:scoped_model/scoped_model.dart';

    class FirstScreen extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _FirstScreenState();
    }

    class _FirstScreenState extends State<FirstScreen>
        with AutomaticKeepAliveClientMixin<FirstScreen> {
      File _image;
      final NameController = TextEditingController();

      @override
      void initState() {
        super.initState();
        print("InitState called") ;
      }

      @override
      // TODO: implement wantKeepAlive
      bool get wantKeepAlive => true;



      @override
      Widget build(BuildContext context) {
        final ProductName = TextFormField(
          controller: NameController,
          autofocus: false,
          obscureText: false,
          decoration: InputDecoration(
            hintText: 'Prodcut Name',
            contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
            border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
          ),
        );




        final AddProduct = Padding(
          padding: EdgeInsets.symmetric(vertical: 16.0),
          child: Column(
            children: <Widget>[
              ScopedModelDescendant<ProductsModel>(
                  rebuildOnChange: false,
                  builder: (context, child, model) => Padding(
                    padding: EdgeInsets.symmetric(vertical: 16.0),
                    child: RaisedButton(
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(24),
                      ),
                      onPressed: (){
                        ModelProduct newProduct = ModelProduct(NameController.text,_image);
                        model.AddNewProduct(newProduct) ;
                        setState(() {
                          NameController.clear();
                          _image = null ;
                        });
                      },
                      padding: EdgeInsets.all(12),
                      color: Colors.lightBlueAccent,
                      child: Text('Add product', style: TextStyle(color: Colors.white)),
                    ),
                  )
              )
            ],

          ),
        );

        Future getImage() async {
          var taken_image = await ImagePicker.pickImage(source: ImageSource.camera);

          setState(() {
            _image = taken_image;
          });
        }

        return Scaffold(
          body: GestureDetector(
            onTap: (){FocusScope.of(context).requestFocus(new FocusNode());},
            child: Container(
              padding: EdgeInsets.all(20),
              child: new ListView(
                children: [
                  SizedBox(height: 20.0),
                  Text(
                    'Add your product here',
                    textAlign: TextAlign.center,
                    overflow: TextOverflow.ellipsis,
                    style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
                  ),
                  SizedBox(height: 20.0),
                  ProductName,
                  SizedBox(height: 20.0),
                  _image == null
                      ? Center(
                          child: new Container(
                              padding: EdgeInsets.all(20),
                              child: Text('No image selected.')))
                      : Image.file(_image),
                  SizedBox(
                    height: 20.0,
                  ),
                  AddProduct,
                ],
              ),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: getImage,
            child: Icon(Icons.camera),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }

Here is my SecondScreen which show the data in ListView

    import 'package:flutter/material.dart';
    import 'package:basicflutter/tabs/FirstScreen.dart';
    import 'package:basicflutter/models/product.dart';
    import 'package:basicflutter/scopedModel/addproduct.dart';
    import 'package:scoped_model/scoped_model.dart';

    class SecondScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
            body: new ScopedModelDescendant<ProductsModel>(
                builder: (context, child, model) => Container(
                      child: new ListView.builder(
                        itemCount: model.count,
                        itemBuilder: (BuildContext context, int index) {
                          return new Card(
                            child: Column(
                              children: <Widget>[
                                Text(model.GetAllProducts[index].name),
                                Container(
                                  width: 250.0,
                                  height: 250.0,
                                  alignment: Alignment.center,
                                  child:

                                  model.GetAllProducts[index].image == null
                                      ? Center(
                                      child: new Container(
                                          padding: EdgeInsets.all(20),
                                          child: Text('No image selected.')))
                                      : Image.file(model.GetAllProducts[index].image ),
                                ),
                              ],
                            ),
                          );
                        },
                      ),
                    )));
      }
    }

Here is my PODO which

import 'dart:io' ;
class ModelProduct {

  String name ;
  File image ;

  ModelProduct(this.name,this.image);

}

And lastly here is my Scoped-Model

import 'package:flutter/material.dart';
import 'package:basicflutter/tabs/FirstScreen.dart';
import 'package:basicflutter/tabs/SecondScreen.dart';
import 'package:basicflutter/models/product.dart';
import 'package:basicflutter/scopedModel/addproduct.dart';
import 'package:scoped_model/scoped_model.dart';
import 'dart:io';

class ProductsModel extends Model {
  final List<ModelProduct> productList = List<ModelProduct>();

  ProductsModel(){
    print("ProductsModel init") ;
  }

  void AddNewProduct(ModelProduct p) {
    productList.add(p);
    notifyListeners() ;
    print(this.count);
  }

  int get count => productList.length ;
  List<ModelProduct> get GetAllProducts => productList ;


}

Solution

  •  Widget build(BuildContext context) {
        return ScopedModel<ProductsModel>(
      model: ProductsModel(),
    

    You've likely solved this by now but... this is your problem. You're initializing your model in the build method. It needs to be initialized outside of that.

    For instance :

    ProductsModel productsModel = ProductsModel();
    
    Widget build(BuildContext context) {
        return ScopedModel<ProductsModel>(
      model: productsModel,