The method 'data' was called on null. Receiver: null Tried calling: data() - flutter

When I try to put the value added to Firebase into the Droppdown button, I get the following error
The method 'data' was called on null.Receiver: nullTried calling: data ()
I think the cause of the error is that I can't call the value from Todo.dart to post_page.dart.
Using debag, todolist is null in post_page.dart.
I would appreciate it if you could answer.
post_page.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import "package:flutter/material.dart";
import 'package:habit_boddy/component/post/task_add_button.dart';
import 'package:habit_boddy/utils/constants.dart';
import 'package:habit_boddy/view/common/components/drop_text.dart';
import 'package:habit_boddy/view/common/components/post_caption_part.dart';
import 'package:habit_boddy/view/post/page/Todo.dart';
import 'package:habit_boddy/view/post/page/detail_page.dart';
import 'package:habit_boddy/view/post/page/picture_page.dart';
import 'package:habit_boddy/view/post/page/task_setting.dart';
import 'package:habit_boddy/view_models/post_view_model.dart';
import 'package:habit_boddy/view_models/todo_view_model.dart';
import 'package:provider/provider.dart';
import 'confirm_dialog.dart';
class PostPage extends StatefulWidget {
#override
_PostPageState createState() => _PostPageState();
}
class _PostPageState extends State<PostPage> {
final _captionController = TextEditingController();
#override
void initState() {
_captionController.addListener(_onCaptionUpdated);
super.initState();
}
#override
void dispose() {
_captionController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ToDoViewModel>(
create:(_) => ToDoViewModel()..getRealtime(),
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.amber,
actions: [
ElevatedButton(
child: Text('Post'),
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onPrimary: Colors.white,
),
onPressed: () => showConfirmedDialog(
context: context,
title: "Post",
content: "May I post?",
onConfirmed: (isConfirmed) {
if (isConfirmed) {
_post(context);
}
}))
],
),
body: Consumer<ToDoViewModel>(builder: (context, model, child) {
final todoList = model.todoList;
return DropdownButton<Todo>(
items: todoList.map((todo) =>
DropdownMenuItem<Todo>(
value: Todo(title: todo.title),
child: Text(todo.title),
)
).toList(),
);
}),
floatingActionButton:
Consumer<ToDoViewModel>(builder: (context, model, child) {
return FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => TaskSetting()),
);
},
child: Icon(Icons.add),
);
}),
),
);
}
_onCaptionUpdated() {
final viewModel = Provider.of<PostViewModel>(context, listen: false);
viewModel.caption = _captionController.text;
print("caption: ${viewModel.caption}");
}
void _post(BuildContext context) {
final postViewModel = Provider.of<PostViewModel>(context, listen: false);
}
}
Widget build(BuildContext context) {
final postViewModel = Provider.of<PostViewModel>(context);
return Container(
child: Padding(
padding: const EdgeInsets.all(40.0),
child: SingleChildScrollView(
child: Column(
children: [
Row(
children: [
Expanded(
flex: 3,
child: Container(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: DropText(),
),
height: 230),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(bottom: 155.0),
child: TaskAdd(),
)),
],
),
Container(
child: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: DetailPost(),
),
height: 270),
Row(
children: [
PicturePage(),
postViewModel.imageFile == null
? Container()
: Container(
height: 60,
width: 60,
child: SingleChildScrollView(
child: PostCaptionPart(
from: PostCaptionOpenMode.FROM_POST,
),
),
)
],
),
],
),
),
),
);
}
Todo.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:habit_boddy/view_models/todo_view_model.dart';
class Todo {
final ToDoViewModel model;
String title = "";
DateTime createdAt;
Todo({DocumentSnapshot doc, this.title, this.model, this.createdAt}){
this.title = doc.data()["title"];
final Timestamp timestamp = doc.data()['createdAt'];
this.createdAt = timestamp.toDate();
}
}

I believe this line is causing the error.
DropdownMenuItem<Todo>(
value: Todo(title: todo.title),
You're calling doc.data() in the Todo constructor without passing the doc variable, hence calling .data() on a null variable. You should instead get the title first, then pass it to the constructor when instantiating the Todo object.
If you really need to pass the doc variable, say if you need it for something else, make it required in the constructor and assert that it is not null.
Todo({#required DocumentSnapshot doc, this.title, this.model, this.createdAt}) : assert(doc != null){
...
}
You should look into Dart null safety as well, which would help to avoid this type of issue.

Related

Should i put CameraController to getxController?

I saw in the getx documents that GetxController is business logic class. When i try to seperate business logic in widget, i have an issue about some controllers such as CameraController, QRViewController,MediaPlayer,... Should i put all things in GetxController or keep this in widget?
qr_code.dart
import 'dart:developer';
import 'dart:io';
import 'package:clean_architecture_getx/controller/qr_code/qr_code_controller.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class QrCodeScreen extends StatefulWidget {
const QrCodeScreen({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _QrCodeScreenState();
}
class _QrCodeScreenState extends State<QrCodeScreen> {
final scanQrController = Get.put(ScanQrController());
QRViewController? qrViewController;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is iOS.
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
qrViewController!.pauseCamera();
}
qrViewController!.resumeCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(
flex: 1,
child: FittedBox(
fit: BoxFit.contain,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Obx(() {
if (scanQrController.result.value.code != null) {
return Text(
'Barcode Type: ${describeEnum(scanQrController.result
.value.format)} Data: ${scanQrController.result
.value.code}');
} else {
return const Text('Scan a code');
}
}),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: qrViewController?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.flipCamera();
setState(() {});
},
child: FutureBuilder(
future: qrViewController?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(
snapshot.data!)}');
} else {
return const Text('loading');
}
},
)),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.pauseCamera();
},
child: const Text('pause',
style: TextStyle(fontSize: 20)),
),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await qrViewController?.resumeCamera();
},
child: const Text('resume',
style: TextStyle(fontSize: 20)),
),
)
],
),
],
),
),
)
],
),
);
}
Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery
.of(context)
.size
.width < 400 ||
MediaQuery
.of(context)
.size
.height < 400)
? 150.0
: 300.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.qrViewController = controller;
});
controller.scannedDataStream.listen((scanData) {
debugPrint('barcode: ${scanData.code}');
scanQrController.updateBarCode(scanData);
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
qrViewController?.dispose();
super.dispose();
}
}
qr_code_controller.dart
import 'package:get/get.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQrController extends GetxController {
final result = Barcode(null, BarcodeFormat.unknown, null).obs;
void onQrViewCreated(QRViewController controller) {}
void updateBarCode(Barcode barcode) {
result.value = barcode;
}
}
Should i put QRViewController to ScanQrController (GetxController) or keep it in widget?
Put the UI in a view, and put the business logic inside a controller. Have a GetX Controller per feature. It would be more helpful if you could provide an example of your code.

Flutter : i want to pass (title,details,content) to details page display it in vertically in top of the details page?

eg: details about the questions ......................................................when i click to a gridview item i want to pass (title,details,content) to details page display in vertically in top of the details page but when i am pass the data not able to fetch the data in details page i created a constrctor in details page not able to set the data in text and image.
Home Page
----------
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'DetailsPage.dart';
var paddingBottom = 48.0;
class HomePage extends StatelessWidget {
final String apiUrl = "https://www.sofikart.com/MobileApi/banners";
final String apiUrl1 =
"https://wayindia.net/indigo/odia_rashifal/rasifhala.php";
Future<List<dynamic>> fetchUsers() async {
var result = await http.get(Uri.parse(apiUrl1));
return json.decode(result.body)['data'];
}
String id(dynamic user) {
return user['id'];
}
String title(dynamic user) {
return user['title'];
}
String content(dynamic user) {
return user['content'];
}
String eng_title(dynamic user) {
return user['eng_title'];
}
String main_img(dynamic user) {
return user['main_img'];
}
String image_2(dynamic user) {
return user['image_2'];
}
String image_3(dynamic user) {
return user['image_3'];
}
String image_4(dynamic user) {
return user['image_4'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ଆଜିର ରାଶିଫଳ'),
centerTitle: true,
),
body: Container(
child: FutureBuilder<List<dynamic>>(
future: fetchUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
print(id(snapshot.data[0]));
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 20,
mainAxisSpacing: 25,
),
padding: EdgeInsets.all(13),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return InkWell(
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Column(
children: [
Expanded(
flex: 9,
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(12)),
child: Image.network(
snapshot.data[index]['main_img'],
fit: BoxFit.fill)),
),
Expanded(
flex: 2,
child: Text(
title(snapshot.data[index]),
style: TextStyle(
color: Colors.black, fontSize: 17),
)),
],
),
),
onTap: () {
print("Click event on Container");
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => DetailsPage()), (route) => false);
},
);
},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}
Details Page
------------
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:odia_rasiphala/HomePage.dart';
import 'dart:convert';
class DetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: new Scaffold(
appBar: new AppBar(
title: new Text('ଆଜିର ରାଶିଫଳ'),
leading: new IconButton(
icon: new Icon(Icons.arrow_back_outlined),
onPressed: () => Navigator.pushReplacement(context,
new MaterialPageRoute(builder: (context) => HomePage())),
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.share),
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image.network(
'',
width: 200.0,
height: 200.0,
),
new Center(
child: new Text('',style: TextStyle(
color: Colors.black,fontSize: 17
)),
)
],
),
));
}
}
I am guessing you want to pass "eng_title" and "main_img" to details screen.
To do that first make a constructor in your details pages. Example:
class DetailScreen extends StatelessWidget {
// In the constructor, require a Todo.
const DetailScreen({Key? key, required this.eng_title, required this.main_img}) : super(key: key);
// Declare a field that holds the strings passed to this class.
final String eng_title;
final String main_img;
#override
Widget build(BuildContext context) {
// Use the final parameters to create the UI.
return Scaffold(
appBar: AppBar(
title: Text(eng.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(main_img),
),
);
}
}
on your OnTap function, when you click an item on the list, just pass the required parameters like this
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(eng_title: snapshot.data[index]['eng_title'], main_img: snapshot.data[index]['main_img']),
),
);
},
This way you can pass data from onescreen to another. Do not use push and remove until, if you want the user to go back to the list in homepage.
For more info about passing data read the following article by flutter:
https://docs.flutter.dev/cookbook/navigation/passing-data

Trying to display username on Homepage using Flutter

Using the following code, I am able to retrieve the username of the currently logged in user but when I try to display it, it displays as null.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:localeventsapp/Screens/Login/login_screen.dart';
import 'package:localeventsapp/model/category.dart';
import 'package:localeventsapp/model/event.dart';
import 'package:localeventsapp/styleguide.dart';
import 'package:localeventsapp/ui/event_details/event_details_page.dart';
import 'package:localeventsapp/ui/homepage/form_widget.dart';
import 'package:provider/provider.dart';
import '../../app_state.dart';
import '../../authentication_service.dart';
import 'category_widget.dart';
import 'event_widget.dart';
import 'home_page_background.dart';
CollectionReference users = FirebaseFirestore.instance.collection("Users");
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
// String uName = getUsername(uid).toString();
String getUsername(String uid) {
String username;
DocumentReference documentReference = users.doc(uid);
documentReference.get().then((snapshot) {
username = snapshot.data()['displayName'].toString();
print("Username is " + username);
});
return username;
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider<AppState>(
create: (_) => AppState(),
child: Stack(
children: <Widget>[
HomePageBackground(
screenHeight: MediaQuery.of(context).size.height,
),
SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Row(
children: <Widget>[
Text(
"TuLink",
style: fadedTextStyle,
),
Spacer(),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Text(
getUsername(uid).toString(),
style: whiteHeadingTextStyle,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Consumer<AppState>(
builder: (context, appState, _) =>
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
for (final category in categories)
CategoryWidget(category: category),
],
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Consumer<AppState>(
builder: (context, appState, _) => Column(
children: <Widget>[
for (final event in events.where((e) => e
.categoryIds
.contains(appState.selectedCategoryId)))
GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
EventDetailsPage(event: event),
),
);
},
child: EventWidget(
event: event,
),
)
],
),
),
),
FloatingActionButton.extended(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => FormPage()));
},
label: Text('Create'),
icon: Icon(Icons.create),
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))),
backgroundColor: Color(0xFF6F35A5),
),
ElevatedButton(
child: Text('Sign Out',
style: TextStyle(
color: Colors.black,
fontSize: 16,
)),
onPressed: () {
context.read<AuthenticationService>().signOut();
Navigator.of(context).push(MaterialPageRoute(builder: (context) => LoginScreen()));
}),
],
),
),
),
],
),
),
);
}
}
class CircularButton extends StatelessWidget {
final double width;
final double height;
final Color color;
final Icon icon;
final Function onClick;
CircularButton(
{this.color, this.width, this.height, this.icon, this.onClick});
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
width: width,
height: height,
child: IconButton(
icon: icon,
enableFeedback: true,
onPressed: onClick,
),
);
}
}
Specifically this part :
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Text(
getUsername(uid).toString(),
style: whiteHeadingTextStyle,
),
),
The "getUsername(uid).toString()" portion returns a null here.
This is the getUsername method:
String getUsername(String uid) {
String username;
DocumentReference documentReference = users.doc(uid);
documentReference.get().then((snapshot) {
username = snapshot.data()['displayName'].toString();
print("Username is " + username);
});
return username;
}
But print returns the name just fine. I'm kind of stumped.
Any ideas?
Just add a setState before your return statement
setState({}); /// only works in a statefulWidget
return username;
This is happening because by the time your fetch username the build method runs and the Ui is built that means username is displayed as null in the Ui, but when the username is fetched the variable has the value but its not displayed on screen because you need to redraw the widgets in order to show the updated value on the screen by calling setState thats how flutter works.I would recommend you to play around with the flutters counter app and try to add print statements and remove setState.
Although SetState might not be the best solution there are different techniques though but setState is a good place to start
And then later you could move on to using widgets like
ValueListenableBuilder, FutureBuilder etc

Flutter: A build function returned null

I have a StatefulWidget for displaying page with data, and I am using setState for returning the page, but when I am running apps show error like this:
[1] : https://imgur.com/a/7bJJSLI "screenshot"
this is my code
import 'package:flutter/material.dart';
import 'package:codelab_dicoding/data.dart';
import 'package:codelab_dicoding/detail.dart';
class BreakFast extends StatefulWidget{
#override
_BreakFastState createState() => _BreakFastState();
}
class _BreakFastState extends State<BreakFast>{
List<Container> daftarBreakfast = List();
#override
Widget build(BuildContext context) {
// TODO: implement build
Future <_BreakFastState>_breakfast() async {
for (var i = 0; i < breakfast.length; i++) {
final namaMakanan = breakfast[i];
final String gambar = namaMakanan["gambar"];
final String bahan = namaMakanan["bahan"];
daftarBreakfast.add(Container(
padding: EdgeInsets.all(10.0),
child: Card(
child: Column(
children: <Widget>[
Expanded(
// tag: namaMakanan['nama'],
child: Material(
child: InkWell(
onTap: () =>
Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context) => Detail(
nama: namaMakanan['nama'],
gambar: gambar,
bahan: bahan
),
)),
child: Image.network(
gambar,
fit: BoxFit.cover,
),
),
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Text(
namaMakanan['nama'],
style: new TextStyle(fontSize: 20.0),
)
],
))));
}
}
setState(() {
return BreakFast();
});
}
}
Is there something wrong with my code? I just omitted some variables for simplicity.
There are couple of mistakes you were making, like you were using setState inside build() and you also had your _breakfast() inside the build(). Check out this code, it is working.
class BreakFast extends StatefulWidget {
#override
_BreakFastState createState() => _BreakFastState();
}
class _BreakFastState extends State<BreakFast> {
List<Container> daftarBreakfast = List();
// put it outside build()
Future<_BreakFastState> _breakfast() async {
for (var i = 0; i < breakfast.length; i++) {
final namaMakanan = breakfast[i];
final String gambar = namaMakanan["gambar"];
final String bahan = namaMakanan["bahan"];
daftarBreakfast.add(Container(
padding: EdgeInsets.all(10.0),
child: Card(
child: Column(
children: <Widget>[
Expanded(
// tag: namaMakanan['nama'],
child: Material(
child: InkWell(
onTap: () => Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context) => Detail(nama: namaMakanan['nama'], gambar: gambar, bahan: bahan),
)),
child: Image.network(
gambar,
fit: BoxFit.cover,
),
),
),
),
Padding(
padding: EdgeInsets.all(10.0),
),
Text(
namaMakanan['nama'],
style: new TextStyle(fontSize: 20.0),
)
],
))));
}
}
#override
Widget build(BuildContext context) {
// return BreakFast();
return FlutterLogo(size: 400); // try this
}
}

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