Flutter URL Launcher Google Maps - dart

List.dart
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class List extends StatefulWidget {
#override
ListState createState() {
return new ListState();
}
}
class ListState extends State<List> {
static const double lat = 2.813812, long = 101.503413;
static const String map_api= "API_KEY";
#override
Widget build(BuildContext context) {
//method to launch maps
void launchMap() async{
const url = "https://maps.google.com/maps/search/?api=$map_api&query=$lat,$long";
if (await canLaunch(url)) {
print("Can launch");
void initState(){
super.initState();
canLaunch( "https://maps.google.com/maps/search/?api=$map_api&query=$lat,$long");
}
await launch(url);
} else {
print("Could not launch");
throw 'Could not launch Maps';
}
}
//method to bring out dialog
void makeDialog(){
showDialog(
context: context,
builder: (_) => new SimpleDialog(
contentPadding: EdgeInsets.only(left: 30.0, top: 30.0),
children: <Widget>[
new Text("Address: ",
style: TextStyle(
fontWeight: FontWeight.bold
),
),
new ButtonBar(
children: <Widget>[
new IconButton(
icon: Icon(Icons.close),
onPressed: (){
Navigator.pop(context);
}
)
],
)
],
)
);
}
return new Scaffold(
body: new ListView.builder(
itemBuilder: (context, index) => ExpansionTile(
title: new Text("State ${index+1}"),
children: <Widget>[
new ListTile(
title: new Text("Place 1"),
trailing: new Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new IconButton(
icon: Icon(Icons.info),
onPressed: makeDialog
),
new IconButton(
icon: Icon(Icons.directions),
onPressed: launchMap
)
],
),
),
new Divider(height: 10.0),
new ListTile(
title: new Text("Place 2"),
trailing: new Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new IconButton(
icon: Icon(Icons.info),
onPressed: makeDialog
),
new IconButton(
icon: Icon(Icons.directions),
onPressed: launchMap
)
],
),
)
],
),
itemCount: 5,
),
);
}
}
My project currently involves launching Google Maps from the URL launcher library. But the problem I am currently having is Google Maps will open but it does not open to the latitude and longitude that I have set as the variable.
How do i set the URL for it to launch according to the coordinates? Or is there a better alternative?
Please assist.

You need to pass api=1 for url_launcher, you have to pass the encoded url Uri.encodeFull().
find more details in this sample project.
launchURL() async {
static const String homeLat = "37.3230";
static const String homeLng = "-122.0312";
static final String googleMapslocationUrl = "https://www.google.com/maps/search/?api=1&query=${TextStrings.homeLat},${TextStrings.homeLng}";
final String encodedURl = Uri.encodeFull(googleMapslocationUrl);
if (await canLaunch(encodedURl)) {
await launch(encodedURl);
} else {
print('Could not launch $encodedURl');
throw 'Could not launch $encodedURl';
}
}

You can use a Map Launcher plugin
if (await MapLauncher.isMapAvailable(MapType.google)) {
await MapLauncher.launchMap(
mapType: MapType.google,
coords: Coords(31.233568, 121.505504),
title: "Shanghai Tower",
description: "Asia's tallest building",
);
}

try this method
///
/// for launching map with specific [latitude] and [longitude]
static Future<void> openMap({
required double latitude,
required double longitude,
required String label,
}) async {
final query = '$latitude,$longitude($label)';
final uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
await launch(uri.toString());
}

For launching Google Maps, the format[1] for a simple search should be as followed:
https://www.google.com/maps/search/?api=1&query=ADDRESS_OR_LATLNG_HERE
In your case, instead of having the value of 1 for the api parameter, you are inserting "API_KEY", which is incorrect. The value should always be 1, so this can be hard-coded.
[1] https://developers.google.com/maps/documentation/urls/guide#forming-the-url

Related

Flutter firebase upload photo problem on IOS devices

I want to upload an image from the gallery in flutter. Android devices are worikng perfectly However when I click on the change button on Ios devices, I get an error "Another exception was thrown: LateInitializationError: Field 'indirmeBaglantisi' has not been initialized."
What could be causing this error? Here is my code:
class _AyarlarState extends State<Ayarlar> {
final AuthService _auth = AuthService();
FirebaseAuth auth = FirebaseAuth.instance;
late String indirmeBaglantisi;
late File yuklenecekDosya;
#override
void initState(){
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) => baglantiAl());
}
baglantiAl() async {
String baglanti = await FirebaseStorage.instance
.ref()
.child("profilresimleri")
.child(auth.currentUser!.uid)
.child("profilResmi.png").getDownloadURL();
setState(() {
indirmeBaglantisi = baglanti;
});
}
kameradanYukle() async {
// ignore: deprecated_member_use
var alinanDosya = await ImagePicker().getImage(source: ImageSource.gallery);
setState(() {
yuklenecekDosya = File(alinanDosya!.path);
});
Reference referansYol = FirebaseStorage.instance
.ref()
.child("profilresimleri")
.child(auth.currentUser!.uid)
.child("profilResmi.png");
UploadTask yuklemeGorevi = referansYol.putFile(yuklenecekDosya);
String url = await (await yuklemeGorevi).ref.getDownloadURL();
setState(() {
indirmeBaglantisi = url;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.black,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Color(0XFF1E1E37),
),
),
Padding(
padding: EdgeInsets.only(top:130),
child: Column(
children: <Widget> [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget> [
Container(
child: Row(
children: [
ClipOval(
child: indirmeBaglantisi == null ? Image.asset("assets/images/Oval2.png") : Image.network(indirmeBaglantisi,height: 100,width:100 ,fit:BoxFit.fitWidth),
)
],
),
),
],
),
SizedBox(height: 20),
// ignore: deprecated_member_use
RaisedButton.icon(
padding: EdgeInsets.symmetric(vertical: 8.0,horizontal: 10.0),
onPressed: () {
kameradanYukle();
},
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30)),
) ,
icon: Icon(Icons.insert_photo_outlined, color: Colors.blue,), label: Text('Profil Fotoğrafını Değiştir'),
color: Colors.white,
),
It's likely that you forgot to ask for permission to use the user's photo library as that is something you must do on IOS.
Go to your IOS folder and inside of that go to the Runner folder. Find the info.plist file and add in the following:
<key>NSPhotoLibraryUsageDescription</key>
<string>Allow access to photo library?</string>
You can replace the second line's text with whatever you want the user to see.

How to pass down data from Stateful classes to another Stateful class that exists in another file?

I'm having trouble passing the data that's been filled in a textformfields and selected in a dropdown menu.
I'm trying to use the Map function to pass down String values so that I can also pass down all types of values in the future (ex. int, bool, double etc.), however it's not working so I need someone to check it out.
main.dart
import 'package:flutter/material.dart';
import 'package:workoutapp/auth/auth.dart';
import 'package:workoutapp/auth/root_page.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
void main(List<String> args) {
runApp(
WorkoutManager(),
);
}
class WorkoutManager extends StatelessWidget {
#override
Widget build(BuildContext context) {
return AuthProvider(
auth: Auth(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Workout Manager',
home: RootPage(),
theme: ThemeData(
primaryColor: Colors.indigo,
primarySwatch: Colors.indigo,
accentColor: Colors.indigoAccent,
hintColor: Colors.indigo,
brightness: Brightness.dark,
),
),
);
}
}
HomePage
import 'package:flutter/material.dart';
import 'package:workoutapp/inheritedWigets/auth_provider.dart';
import './profile_account_page.dart';
import './routines_create_page.dart';
import '../objects/Routines/routines_manager.dart';
import '../tools/custom_drawer.dart';
class HomePage extends StatelessWidget {
final VoidCallback onSignedOut;
final List<Map<String, String>> routines;
HomePage({Key key, this.onSignedOut, this.routines}) : super(key: key);
void _signedOut(BuildContext context) async {
try {
var auth = AuthProvider.of(context).auth;
await auth.signOut();
onSignedOut();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Workout Manager', style: TextStyle(color: Colors.white)),
centerTitle: false,
actions: <Widget>[
FlatButton(
child: Text('Logout'),
onPressed: () {
return _signedOut(context);
},
),
IconButton(
icon: Icon(Icons.account_box),
tooltip: 'Profile Account',
color: Colors.white,
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return ProfileAccountPage();
}));
},
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesPageCreate();
}));
},
),
body: RoutinesManager(),
drawer: CustomDrawer(),
);
}
}
RoutineManager
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines.dart';
class RoutinesManager extends StatefulWidget {
final Map<String, String> startingRoutine;
RoutinesManager({this.startingRoutine});
#override
_RoutinesManagerState createState() => _RoutinesManagerState();
}
class _RoutinesManagerState extends State<RoutinesManager> {
List<Map<String, String>> _routines = [];
#override
void initState() {
if (widget.startingRoutine != null) {
_routines.add(widget.startingRoutine);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: Routines(_routines),
)
],
);
}
}
RoutinesCreatePage
import 'package:flutter/material.dart';
import 'package:workoutapp/pages/home_page.dart';
class RoutinesPageCreate extends StatefulWidget {
#override
_RoutinesPageCreateState createState() => _RoutinesPageCreateState();
}
class _RoutinesPageCreateState extends State<RoutinesPageCreate> {
final formKey = GlobalKey<FormState>();
List<Map<String, String>> _routines = [];
String _routineName, _routineDescription;
var _routineNameController = TextEditingController();
var _routineDescriptionController = TextEditingController();
List<DropdownMenuItem<String>> _dropdownListBodyPartMenuItem = [];
List<String> _dropdownListBodyPart = [
'Chest',
'Back',
'Leg',
'Shoulder',
'Abs',
];
String _selectedBodyPart;
List<DropdownMenuItem<String>> _dropdownListDayOfWeekMenuItem = [];
List<String> _dropdownListDayOfWeek = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
String _selectedDayOfWeek;
void loadBodyPartData() {
_dropdownListBodyPartMenuItem = [];
_dropdownListBodyPartMenuItem = _dropdownListBodyPart.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
void loadDayOfWeekData() {
_dropdownListDayOfWeekMenuItem = [];
_dropdownListDayOfWeekMenuItem = _dropdownListDayOfWeek.map((val) {
return DropdownMenuItem<String>(
child: Text(val),
value: val,
);
}).toList();
}
final _scaffoldState = GlobalKey<ScaffoldState>();
void _showSnakBarReset() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Showing SnackBar TEST'),
),
);
}
void _showSnakBarCreateWorkoutRoutine() {
_scaffoldState.currentState.showSnackBar(
SnackBar(
backgroundColor: Theme.of(context).accentColor,
content: Text('Workout Routine has been created'),
),
);
}
void _addRoutine(Map<String, String> routine) {
setState(() {
_routines.add(routine);
});
}
#override
Widget build(BuildContext context) {
loadBodyPartData();
loadDayOfWeekData();
return Scaffold(
key: _scaffoldState,
appBar: AppBar(
title: Text('Create Routines'),
),
body: Container(
padding: EdgeInsets.all(15.0),
child: Form(
key: formKey,
child: ListView(children: buildInputs() + buildCreateButtons()),
),
),
);
}
List<Widget> buildInputs() {
TextStyle textStyle = Theme.of(context).textTheme.title;
return [
TextFormField(
controller: _routineNameController,
validator: (value) {
if (value.length > 20) {
return 'Not a valid Routine Name';
}
},
onSaved: (value) {
return _routineName = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Routine Name',
hintText: 'Enter the Routine Name for this day',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: EdgeInsets.all(7.0)),
TextFormField(
controller: _routineDescriptionController,
validator: (value) {
if (value.length > 50) {
return 'Invalid: The Description must be 50 characters or less.';
}
},
onSaved: (value) {
return _routineDescription = value;
},
decoration: InputDecoration(
labelStyle: textStyle,
labelText: 'Description',
hintText: 'Enter the description of the Routine.',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
))),
Padding(padding: const EdgeInsets.all(7.0)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedBodyPart,
items: _dropdownListBodyPartMenuItem,
hint: Text('Select Body Part', style: textStyle),
onChanged: (value) {
setState(() {
_selectedBodyPart = value;
});
})),
Padding(
padding: const EdgeInsets.all(1.0),
),
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedDayOfWeek,
items: _dropdownListDayOfWeekMenuItem,
hint: Text('Select Day of Week', style: textStyle),
onChanged: (value) {
setState(() {
_selectedDayOfWeek = value;
});
},
),
),
Padding(
padding: const EdgeInsets.all(4.0),
)
],
),
];
}
List<Widget> buildCreateButtons() {
return [
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorDark,
color: Theme.of(context).accentColor,
child: Text('Create Workout Routine'),
onPressed: () {
if (formKey.currentState.validate()) {
_showSnakBarCreateWorkoutRoutine();
formKey.currentState.save();
_addRoutine({
'routineName': 'Chest Workout',
'description': 'Heavy',
'bodyPart': 'Chest',
'week': 'Monday',
});
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return HomePage();
}));
} else {
return null;
}
}),
),
Expanded(
child: RaisedButton(
textColor: Theme.of(context).primaryColorLight,
color: Theme.of(context).primaryColorDark,
child: Text('Reset'),
onPressed: () {
setState(() {
_showSnakBarReset();
formKey.currentState.reset();
_selectedBodyPart = null;
_selectedDayOfWeek = null;
});
},
),
),
],
),
),
];
}
}
Routines
import 'package:flutter/material.dart';
import 'package:workoutapp/objects/routines/routines_detail.dart';
class Routines extends StatelessWidget {
final List<Map<String, String>> routines;
Routines(this.routines);
Widget _buildRoutinesItem(BuildContext context, int index) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Expanded(
child: Card(
margin: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['routineName'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['description'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['bodyPart'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routines[index]['week'], style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(
child: Text('Details'),
onPressed: () {
return Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return RoutinesDetail(
routines[index]['routineName'],
routines[index]['description'],
routines[index]['bodyPart'],
routines[index]['week']);
}));
},
)
],
),
)
],
),
),
);
}
Widget _buildRoutinesList(context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
Widget routinesCards = Container(
child: Container(
child: Center(
child: Text("No routines found, please add some.", style: textStyle),
),
),
);
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}
return routinesCards;
}
#override
Widget build(BuildContext context) {
return _buildRoutinesList(context);
}
}
RoutineDetailPage
import 'package:flutter/material.dart';
class RoutinesDetail extends StatelessWidget {
final String routineName, description, bodyPart, week;
RoutinesDetail(this.routineName, this.description, this.bodyPart, this.week);
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text(routineName),
centerTitle: true,
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(routineName, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(description, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(bodyPart, style: textStyle)),
Padding(
padding: const EdgeInsets.all(5.0),
child: Text(week, style: textStyle)),
Container(
padding: EdgeInsets.all(5.0),
child: RaisedButton(
child: Text('Delete'),
onPressed: () {
Navigator.pop(context);
},
),
),
],
),
),
);
}
}
As you can see, I'm trying to separate the code into multiple files as much as possible, so it's more "readable" and make it easy for myself to make changes to the code whenever I have to in the future.
The problem is, it's quite spit up, I don't understand how to use the data and pass it down or up to the pages or widgets as there are multiple stateful and stateless widgets that are suppose to work together to make this app possible.
You'll notice on the HomePage file (StatelessWidget), I'm trying to show the Scaffold body argument with the RoutinesManager StatefulWidget, which is in a different file. At the same time in the HomePage file, I have a Scaffold floatingActionButton argument that will take you to the RoutinesCreatePage StatefulWidget to create a List of Cards (StatelessWidget) using the ListView.builder(). However, no Card gets created under the HomePage after the "Create Workout Routine" RaisedButton gets pressed in the RoutinesCreatePage and no data gets passed.
Can someone please help me out here as I am totally clueless. Also, I'm fairly a beginner regarding flutter/dart so a solution with a relatively easy to understand explanation would be very helpful.
Note: I do have other files that contribute to this app, however I don't think they're part of the problem so I left them out intentionally.
If more information is needed, please do let me know.
Thanks you!
it looks like you misunderstand what state in Flutter is. To explain in short, state is the internal status/data/... that belongs that that specific widget. StatefulWidget has state to determine if UI should be re-rendered on its own state change. External widgets never know about other widgets' states.
So it means, any state change happening inside RoutinesCreatePage widget, only that RoutinesCreatePage knows and reacts. Unless, you inform other widgets to know something has changed.
Alright, so talking about navigation, it works like a stack structure. HomePage trigger a push to RoutinesCreatePage, then to return, you need to pop, not another push.
Here a quick fix for your code, you can try.
HomePage
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
handleNewRoutine(); <--- this is to handle navigation and retrieve returning data from pop
},
),
Future handleNewRoutine() async {
var newRoutine = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => RoutinesPageCreate());
)
if (newRoutine == null) {
// nothing returns from RoutinesPageCreate widget
// so do nothing then
} else {
// add to routine list
// and trigger list re-rendering
setState(() {
this.routines.add(newRoutine);
});
}
}
RoutinesCreatePage: when clicking submit button, just populate all data from input fields, make object model and pop to return data to where this widget was pushed.
onPressed: () {
var newRoutine = .... // populate from UI to create new Routine model object.
Navigator.pop(context, newRoutine);
}
Also, take time to read the navigation guide from official Flutter documentation. It is very detailed on this part. https://flutter.io/docs/cookbook/navigation/returning-data
Some additional comments to your code:
in RoutinesCreatePage you don't need to know application level state, I mean _routines variable is unnecessary. You only need one object to store new routine to pop back to HomePage.
in Routines, this method Widget _buildRoutinesList(context) having unused ListView creation.
if (routines.length > 0 || routines.length <= 7) {
ListView.builder(
itemBuilder: _buildRoutinesItem,
itemCount: routines.length,
);
}

The following ArgumentError was thrown building Home(dirty, state: _HomeState#3752d): Invalid argument(s)

I am getting dirty state exception when redirecting on a new page after login. On this home page I am getting info from preferences.
class Home extends StatefulWidget{
#override
State<StatefulWidget> createState() => new _HomeState();
}
class _HomeState extends State<Home> {
Drawer drawer = new Drawer();
String strName, strEmail, strImageURL;
int userId;
Image imgProfile;
#override
void initState() {
super.initState();
_loadSharedPref();
}
//Loading Shared value on start
_loadSharedPref() async {
print('In Shared Profile');
try{
SharedPreferences prefs = await SharedPreferences.getInstance();
strName = prefs.getString('name');
print('Shared Profile Name '+strName);
setState(() {
strName = prefs.getString('name');
userId = prefs.getInt('userId');
strEmail = prefs.getString('email');
strImageURL = prefs.getString('avatar');
imgProfile = Image.network(Config.PROFILE_PIC+strImageURL);
print('Image URL ---- '+Config.PROFILE_PIC+strImageURL);
});
}catch(exception){
print('SharedProfile '+exception);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
backgroundColor: whiteColor,
drawer: sideDrawer(),
appBar: new AppBar(
title: new Text('Test Page'),
),
),
);
}
//Profile Details
Widget profileDetail() {
return new DrawerHeader(
child: new Column(
children: <Widget>[
new CircleAvatar(
radius: 40,
backgroundColor : blueColor,
backgroundImage: new NetworkImage(Config.PROFILE_PIC+strImageURL),
),
],
)
);
}
//Side Drawer
Widget sideDrawer(){
return new Drawer(
child: new ListView(
children: <Widget>[
new Center(
child: profileDetail(),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Requests'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Reviews'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Setting'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Tip'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Conditions'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('About Us'),
// onTap: () => _onListTileTap(context),
),
new ListTile(
leading: new Icon(Icons.lightbulb_outline),
title: new Text('Log Out'),
// onTap: () => _onListTileTap(context),
),
],
),
);
}
}
Cross-link https://github.com/flutter/flutter/issues/25428
I went into the same kind of problem. Checking my variables having shared pref values for null or not worked for me.
Try checking strName, userId, strEmail, strImageURL, imgProfile are not null before using them in the widget.
if(strImageURL != null)
{
print('filepaths: '+strImageURL);
}
Try this out
//Profile Details
Widget profileDetail() {
return new DrawerHeader(
child: new Column(
children: <Widget>[
new CircleAvatar(
radius: 40,
backgroundColor : blueColor,
backgroundImage: strImageURL ?? AssetImage('some static file path') : NetworkImage(Config.PROFILE_PIC+strImageURL),
),
],
)
);
}
You probably didn't fill "name", "userId", "avatar" or "email" fields in your preferences and you are getting this error when trying to get with SharedPreferences.
just create statement everytime you trying to call the data from sharedPreference like this
body: yourDatainsharedPreference != null ?
//do something
:
// do something

Destruct and Construct cards in Flutter dynamically

I'm new to Flutter,
I want to destruct cards created initially and construct them again as per data provided in API call.
Basically when I tap on button in UI, it should call APIs and based on data from API call, if it is different from the data I already have, I want to destruct cards and construct them again.
How I can achieve this?
The cards will auto update their content when you make the call again, it is like refreshing your data.
I have made a simple example with a single card that shows data from this JSON Where I am calling the API first time in initState and then repeating the call each time I press on the FAB.
I am adding the index variable just to show you the updates (updating my single card with the next item in the list)
Also it is worth noting that I am handling the null or empty values poorly for the sake of time.
Also forget about the UI overflow ¯_(ツ)_/¯
class CardListExample extends StatefulWidget {
#override
_CardListExampleState createState() => new _CardListExampleState();
}
class _CardListExampleState extends State<CardListExample> {
Map cardList = {};
int index = 0;
#override
void initState() {
_getRequests();
super.initState();
}
_getRequests() async {
String url = "https://jsonplaceholder.typicode.com/users";
var httpClinet = createHttpClient();
var response = await httpClinet.get(
url,
);
var data = JSON.decode(response.body);
//print (data);
setState(() {
this.cardList = data[index];
this.index++;
});
print(cardList);
print(cardList["name"]);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton:
new FloatingActionButton(onPressed: () => _getRequests()),
appBar: new AppBar(
title: new Text("Card List Example"),
),
body: this.cardList != {}
? new ListView(children: <Widget>[
new Card(
child: new Column(
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Text(
cardList["name"] ?? '',
style: Theme.of(context).textTheme.display1,
),
new Text(
this.cardList['email'] ?? '',
maxLines: 50,
),
],
),
new Text(cardList["website"] ?? '')
],
),
),
])
: new Center(child: new CircularProgressIndicator()),
);
}
}
Yes, Answer from Aziza works.
Though I used the code as below :
void main() =>
runApp(new MaterialApp(
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/about':
return new FromRightToLeft(
builder: (_) => new _aboutPage.About(),
settings: settings,
);
}
},
home : new HomePage(),
theme: new ThemeData(
fontFamily: 'Poppins',
primarySwatch: Colors.blue,
),
));
class HomePage extends StatefulWidget{
#override
HomePageState createState() => new HomePageState();
}
class HomePageState extends State<HomePage>{
List data;
Future<String> getData() async{
var response = await http.get(
Uri.encodeFull(<SOMEURL>),
headers: {
"Accept" : "application/json"
}
);
this.setState((){
data = JSON.decode(response.body);
});
return "Success";
}
#override
void initState() {
// TODO: implement initState
super.initState();
this.getData();
}
#override
Widget build(BuildContext context){
return new Scaffold(
appBar : new AppBar(
title : new Text("ABC API"),
actions: <Widget>[
new IconButton( // action button
icon: new Icon(Icons.cached),
onPressed: () => getData(),
)],
),
drawer: new Drawer(
child: new ListView(
children: <Widget> [
new Container(
height: 120.0,
child: new DrawerHeader(
padding: new EdgeInsets.all(0.0),
decoration: new BoxDecoration(
color: new Color(0xFFECEFF1),
),
child: new Center(
child: new FlutterLogo(
colors: Colors.blueGrey,
size: 54.0,
),
),
),
),
new ListTile(
leading: new Icon(Icons.chat),
title: new Text('Support'),
onTap: () {
Navigator.pop(context);
Navigator.of(context).pushNamed('/support');
}
),
new ListTile(
leading: new Icon(Icons.info),
title: new Text('About'),
onTap: () {
Navigator.pop(context);
Navigator.of(context).pushNamed('/about');
}
),
new Divider(),
new ListTile(
leading: new Icon(Icons.exit_to_app),
title: new Text('Sign Out'),
onTap: () {
Navigator.pop(context);
}
),
],
)
),
body: this.data != null ?
new ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index){
return new Container(
padding: new EdgeInsets.fromLTRB(8.0,5.0,8.0,0.0),
child: new Card(
child: new Padding(
padding: new EdgeInsets.fromLTRB(10.0,12.0,8.0,0.0),
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
enabled: data[index]['active'] == '1' ? true : false,
title: new Text(data[index]['header'],
style:Theme.of(context).textTheme.headline,
),
subtitle: new Text("\n" + data[index]['description']),
),
new ButtonTheme.bar(
child: new ButtonBar(
children: <Widget>[
new FlatButton(
child: new Text(data[index]['action1']),
onPressed: data[index]['active'] == '1' ? _launchURL :null,
),
],
),
),
],
),
),
),
);
},
)
:new Center(child: new CircularProgressIndicator()),
);
}
}
_launchURL() async {
const url = 'http://archive.org';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
class FromRightToLeft<T> extends MaterialPageRoute<T> {
FromRightToLeft({ WidgetBuilder builder, RouteSettings settings })
: super(builder: builder, settings: settings);
#override
Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (settings.isInitialRoute)
return child;
return new SlideTransition(
child: new Container(
decoration: new BoxDecoration(
boxShadow: [
new BoxShadow(
color: Colors.black26,
blurRadius: 25.0,
)
]
),
child: child,
),
position: new Tween(
begin: const Offset(1.0, 0.0),
end: const Offset(0.0, 0.0),
)
.animate(
new CurvedAnimation(
parent: animation,
curve: Curves.fastOutSlowIn,
)
),
);
}
#override Duration get transitionDuration => const Duration(milliseconds: 400);
}
The above code includes Navigation drawer, page navigation animation and also answer to the above question.

Failed assertion: line 3927 pos 14: '_dependents.isEmpty': is not true

I am back again with the issue related to the question already posted by me on stack overflow Error: '_elements.contains(element)': is not true
this issue has been plaguing me but i was unable to reproduce the same issue and now i have somehow tried to repro again and I have posted the code for everyone to figure out what is it that i am doing wrong that's throwing up this assertion error and crashing the app.
I am new to programming and any help would be greatly appreciated. I have trimmed down the code and I am aware of the some of the bugs. But, the only main concern is the Failed assertion: line 3927 pos 14: '_dependents.isEmpty': is not true. and Failed assertion: line 1766 pos 12: '_elements.contains(element)': is not true.
Steps to reproduce.
main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:untitled1/addnewbranch.dart';
void main() {
runApp(
new MaterialApp(
home: new Branches(),
),
);
}
class ProjectModel {
BranchSetUpModelData branchesModel;
ProjectModel(this.branchesModel);
}
class BranchSetUpModelData {
String branchName;
String hostelType;
String area;
String city;
BranchSetUpModelData(this.branchName, this.hostelType, this.area, this.city);
}
DatabaseReference _branchesRef;
List<ProjectModel> projectModel = new List();
Map data = {};
List<String> mapKeys = new List();
DataSnapshot dataSnapshot;
class Branches extends StatefulWidget {
//const BranchView({ Key key }) : super(key: key);
const Branches({Key key}) : super(key: key);
#override
_BranchesState createState() => new _BranchesState();
}
class _BranchesState extends State<Branches> {
String userUid = '';
String text;
int noOfBranches = 0;
int itemCount;
Future<Null> getUserUid() async {
try {
//FirebaseUser user = await FirebaseAuth.instance.currentUser();
//userUid = user.uid;
//print(userUid);
_branchesRef =
FirebaseDatabase.instance.reference().child('data').child('branches');
print('branchesref = $_branchesRef');
if (_branchesRef != null) {
try {
_branchesRef.once().then((DataSnapshot snapShot) {
dataSnapshot = snapShot;
print(snapShot is Map);
print(dataSnapshot.value);
data = dataSnapshot.value;
print(data is Map);
print(data);
data.forEach((key, value) {
mapKeys.add(key);
});
print('no of branches = $noOfBranches');
projectModel.clear();
mapKeys.forEach((value) {
_branchesRef.child(value).once().then((DataSnapshot b) {
data = b.value;
data.keys.forEach((k) {
BranchSetUpModelData x = new BranchSetUpModelData(
b.value['branchDetails']['branchName'],
b.value['branchDetails']['hostelType'],
b.value['branchDetails']['area'],
b.value['branchDetails']['city'],
);
print('details from for each loop');
ProjectModel projectModelData = new ProjectModel(x);
projectModel.add(projectModelData);
});
print('projectmodel length = ${projectModel.length}');
});
});
setState(() {
noOfBranches = mapKeys.length;
itemCount = noOfBranches;
});
print('no of branches = $noOfBranches');
data.keys.forEach((k) {
print('inside this foreach loop');
print(k);
});
});
} catch (Exception) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(Exception.message.toString())));
}
} else {
print('user does not exist');
}
} catch (Exception) {
print(Exception.toString());
showDialog(
context: context,
child: new AlertDialog(
content: new Text(Exception.toString()),
));
}
}
#override
void initState() {
super.initState();
mapKeys.clear();
FirebaseDatabase.instance.setPersistenceEnabled(true);
FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000);
getUserUid();
/*setState((){
noOfBranches = mapKeys.length;
});*/
print('noOfBranches in init state= $noOfBranches');
}
#override
Widget build(BuildContext context) {
print('noof branches inside widget build = $noOfBranches');
//if(noOfBranches!=0) {
return new MaterialApp(
title: 'Branches',
theme: new ThemeData(
primaryColor: const Color(0xFF229E9C),
),
home: new Scaffold(
appBar: new AppBar(
title: const Text('Branches'),
backgroundColor: Colors.teal[300],
),
floatingActionButton: new FloatingActionButton(
heroTag: 'branchesHeroTag',
child: new Icon(Icons.add),
backgroundColor: Colors.teal[300],
onPressed: (() {
Navigator.push(
context,
new MaterialPageRoute(
builder: (_) => new AddNewBranch(),
),
);
}),
tooltip: 'Add Branch',
),
body: new Container(
child: new ListView.builder(
padding: const EdgeInsets.only(
left: 4.0,
right: 4.0,
),
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
if (noOfBranches != 0) {
// children: <Widget>[
return new InkWell(
onTap: (() {
/*Navigate here to a different page*/
}),
child: new Card(
child: new Column(
children: <Widget>[
new Container(
//margin: const EdgeInsets.only(top:16.0),
padding: const EdgeInsets.only(top: 16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new Row(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(
left: 16.0,
right: 8.0,
top: 4.0,
bottom: 4.0),
child: new IconButton(
icon: new Icon(Icons.call),
onPressed: (() {}))),
new Container(
child: new Text(
'80/125',
style: new TextStyle(
fontSize: 18.0,
),
),
),
],
),
),
new Expanded(
child: new Row(
textDirection: TextDirection.rtl,
children: [
new Container(
margin:
const EdgeInsets.only(right: 16.0),
child: new Text(
projectModel[index]
.branchesModel
.hostelType,
style: new TextStyle(
fontSize: 18.0,
),
),
),
],
),
),
],
),
),
new Container(
margin:
const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 4.0),
child: new Row(children: <Widget>[
new Text(
projectModel[index].branchesModel.branchName,
style: new TextStyle(
fontSize: 24.0,
),
),
]),
),
new Container(
margin: const EdgeInsets.only(
left: 16.0, right: 16.0, bottom: 8.0),
child: new Row(
children: <Widget>[
new Text(projectModel[index].branchesModel.city),
],
),
),
],
),
),
); // InkWell ends here so this has to go into ListView.builder
} else {
itemCount = 1;
return new Center(
child: new Column(
// mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Setup your Hostel',
style: new TextStyle(
fontSize: 24.0,
color: Colors.grey[400],
fontWeight: FontWeight.bold,
),
),
new Text(
'Please click below + icon to Setup your Hostel',
style: new TextStyle(
fontSize: 16.0,
color: Colors.grey[400],
),
),
],
),
);
}
},
), // ListView.builder ends here.
),
),
);
}
}
globals.dart
library my_app.globals;
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
final FirebaseAuth auth = FirebaseAuth.instance;
final DatabaseReference databaseReference = FirebaseDatabase.instance.reference();
addnewbranch.dart
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:untitled1/main.dart';
import './globals.dart' as gl;
class BranchSetupModel {
String branchName;
String hostelType;
String area;
String city;
BranchSetupModel(this.branchName, this.hostelType, this.area, this.city);
}
BranchSetupModel branchSetupModel =
new BranchSetupModel('', 'Hostel Type', '', '');
class AddNewBranch extends StatefulWidget {
const AddNewBranch({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return new _AddNewBranchState();
}
}
class _AddNewBranchState extends State<AddNewBranch> {
String actionsString = 'Next';
String userUid;
TextEditingController _branchNameController = new TextEditingController();
TextEditingController _areaController = new TextEditingController();
TextEditingController _cityController = new TextEditingController();
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool _formWasEdited = false;
bool _autovalidate = false;
String dropDownvalue = 'Hostel Type';
//FocusNode _branchManagerNameFocusNode = new FocusNode();
String _validateName(String value) {
_formWasEdited = true;
if (value.isEmpty) return 'Name is required.';
final RegExp nameExp = new RegExp(r'^[A-Za-z ]+$');
if (!nameExp.hasMatch(value))
return 'Please enter only alphabetical characters and spaces.';
return null;
}
Future<Null> getUserUid() async {
try {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
userUid = user.uid;
print(userUid);
} catch (Exception) {
print(Exception.toString());
}
}
#override
void initState() {
super.initState();
getUserUid();
_branchNameController =
new TextEditingController(text: branchSetupModel.branchName);
_areaController = new TextEditingController(text: branchSetupModel.area);
_cityController = new TextEditingController(text: branchSetupModel.city);
dropDownvalue = branchSetupModel.hostelType;
branchSetupModel = new BranchSetupModel('', 'Hostel Type', '', '');
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.teal,
),
title: 'Branch Setup',
home: new Scaffold(
appBar: new AppBar(
title: const Text('Add New Branch'),
backgroundColor: Colors.teal[300],
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: (() {
print('back button clicked');
//to be removed and to include functionality here
Navigator.push(
context,
new MaterialPageRoute(
builder: (_) => new Branches(),
),
);
}),
),
actions: <Widget>[
new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new FlatButton(
child: new Text(
actionsString,
style: new TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
onPressed: () {
print('Save button clicked');
String pushKey = gl.databaseReference
.child('data')
.child('branches')
.push()
.key;
gl.databaseReference
.child('data')
.child('branches')
.child(pushKey)
.child('branchDetails')
.set({
"branchName": branchSetupModel.branchName,
"hostelType": branchSetupModel.hostelType,
"area": branchSetupModel.area,
"city": branchSetupModel.city,
"pushKey": pushKey
});
Navigator.push(
context,
new MaterialPageRoute(
builder: (_) => new Branches(),
),
);
},
splashColor: const Color(0xFF229E9C),
),
],
),
),
],
),
body: new Form(
key: _formKey,
child: new ListView(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(left: 16.0, right: 16.0),
child: new Row(
children: <Widget>[
new Text('Hostel Type'),
],
),
),
new Container(
//height: 56.0,
margin: const EdgeInsets.only(left: 16.0, right: 16.0),
child: new Column(
children: <Widget>[
new DropdownButton<String>(
//key: _dropDownKey,
hint: new Text(dropDownvalue),
items: <String>[
'Mens',
'Womens',
].map(
(String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
},
).toList(),
onChanged: (String value) {
setState(() {
dropDownvalue = value;
branchSetupModel.hostelType = value;
print(branchSetupModel.hostelType);
});
},
),
],
),
),
new Container(
margin: const EdgeInsets.only(left: 16.0, right: 16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
autocorrect: false,
decoration: new InputDecoration(
labelText: 'Branch Name',
),
controller: _branchNameController,
onChanged: (String value) {
branchSetupModel.branchName =
_branchNameController.text;
print(branchSetupModel.branchName);
},
//validator: _validateName,
),
),
],
),
),
new Container(
margin: const EdgeInsets.only(left: 16.0, right: 16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
decoration: new InputDecoration(
labelText: 'Area/Location',
),
controller: _areaController,
onChanged: (String value) {
branchSetupModel.area = value;
print(branchSetupModel.area);
},
//validator: _validateName,
),
),
],
),
),
new Container(
margin: const EdgeInsets.only(
left: 16.0,
right: 16.0,
),
child: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
decoration: new InputDecoration(
labelText: 'City',
),
controller: _cityController,
onChanged: (String value) {
branchSetupModel.city = value;
},
),
),
],
),
),
],
),
),
),
);
}
}
pubspec.yaml
name: untitled1
description: A new Flutter project.
dependencies:
flutter:
sdk: flutter
google_sign_in: ^1.0.1
firebase_analytics: ^0.1.1
firebase_auth: ^0.3.1
firebase_database: ^0.1.2
firebase_storage: ^0.0.7
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
Please integrate the firebase app to run the code before trying to reproduce the error and make sure the read and write access set to 'true' as I have not added any authentication.
As far as I know the error only occurs in the main.dart file.It works fine for a few times and then the errors start coming in. First, it throws up the error RangeError (index): Invalid value: Valid value range is empty: 0 this error is for the ListView.builder() and then the other two assertion errors come up.
Please can someone tell me what I am doing wrong or is there a different way to achieve the same goal without these errors.
output from flutter doctor command.
[√] Flutter (on Microsoft Windows [Version 10.0.15063], locale en-GB, channel alpha)
• Flutter at C:\Users\Prayuta\flutter
• Framework revision e8aa40eddd (3 weeks ago), 2017-10-17 15:42:40 -0700
• Engine revision 7c4142808c
• Tools Dart version 1.25.0-dev.11.0
[√] Android toolchain - develop for Android devices (Android SDK 27.0.0)
• Android SDK at C:\Users\Prayuta\AppData\Local\Android\sdk
• Platform android-27, build-tools 27.0.0
• Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)
[√] Android Studio (version 3.0)
• Android Studio at C:\Program Files\Android\Android Studio
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)
[√] IntelliJ IDEA Community Edition (version 2017.2)
• Flutter plugin version 18.4
• Dart plugin version 172.4343.25
[√] Connected devices
• Android SDK built for x86 • emulator-5554 • android-x86 • Android 7.1.1 (API 25) (emulator)
Process finished with exit code 0.
I recently had the same exception when I was trying to navigate to another route from a Stateful Widget. Turns out I had forgotten to add the line super.initState(); at the start of my widget's initState()
Once I change it to this it worked perfectly
#override
void initState() {
super.initState();
....
}
This error happens due to incorrect widget configuration, so in other words it's not an error itself, but a symptom of another error.
For OP
OP has already found a solution so I won't elaborate on it. Fixing the error in your ListView should do the trick.
TL;DR
Try:
Calling super.initState() inside all your StatefulWidgets.initState() overrides.
Making sure all your Widget.keys are unique.
Making sure all your widgets that use a builder function have no errors. These widgets include AnimatedBuilder, LayoutBuilder, and external packages like GetX or Provider that have a builder, and any packages that depend on them (like Bloc). With these builder widgets, the exception usually occurs when you build the same Widget with different instance members based on some passed value. For example:
...
BlocBuilder<MyBloc, MyState>(
builder: (context, state) => Container(
color: state is SomeState ? Colors.blue : Colors.red, // Something along these lines
),
)
// or
BlocBuilder<MyBloc, MyState>(
builder: (context, state) => state is SomeState ? Container(color: Colors.red) : Container(color: Colors.blue),
)
....
More Explanation
First of all, I want to note that while the exception message is a bit misleading, the flutter team had a couple TODOs to make the exception clearer and refer specifically to the faulty widget.
As the message mentions, the error is related to duplicate GlobalKeys within the widget tree. Usually, this doesn't happen due to directly using the same Key on two different widgets (because devs are usually aware of that). Instead, it hides itself behind other issues such as the ones mentioned above. They all produce similar effect, however: They cause errors in the widget's lifecycle state.
Forgetting to call initState, for instance, messes up the widget's lifecycle state update. I'm not exactly sure exactly where this happens, but it seems that the framework creates duplicate element/widget to the same widget with the same GlobalKey if the widget's lifecycle state is tampered with. This needs further investigation and confirmation.
The thing with builder widgets is that if the first widget to be returned from the builder has an exception, the framework will mount it, but for some reason, the lifecycle change will not occur when the second widget to be returned from builder is inserted in the tree, and both the first and the second widgets end up with the same Key.
In both cases, when the framework unmounts currently active widgets, it checks widgets' lifecycle state, determines which ones are inactive, and ignores them. However, because lifecycle states of some widgets are wrong, it might treat an inactive widget as active, compare it to currently active widgets only to find duplicates, and then throw the exception.
If you want to check that yourself, you can read src/widgets/framework.dart file referred to in the error message, starting from BuilderOwner.finalizeTree() function.
This happened to me as I wrapped a ListView.builder with an Expanded without a container surrounding the Expanded directly as the body of my Scaffold.
For anyone who may find this helpful, I recently had this issue too and it was caused by incorrectly setting a number of key parameters in a list of widgets. I was setting the key based on an id:
key: Key(item.id.toString())
However due to some other logic item.id can sometimes be null and because there are a number of these widgets I ended up with multiple widgets with the key: Key("null"). Updating my key to ensure it was unique solved my problem:
key: Key(items.indexOf(item).toString())
In my case i was using a modalBox. So i created another form key and used it with it. Thats how i solved mine
For me I was declaring my form key inside the initState(). I just moved out as a global variable and it work.
This is my initSatate() now:
#override
void initState() {
super.initState();
}
In my case I had define a component with static key, and I used the component 3 times inside a ListView. So Flutter was find a problem with the position of some components, because the Flutter search by key to verify changes. To solve my problem, I put the property key as optional.
Before:
MyTextField(
{Key key = const Key("textField"),
this.label,
After change:
MyTextField(
{Key? key,
this.label,
...
if you are using provider and GetX both then this error occurs some time and app crash.
Remove one of them if both not neccesory
In my case I was popping a route in which I was passing arguments like this to fix another problem (this was more of a dummy argument), once I removed the arguments, the problem went away
onPressed: () {
Navigator.of(context)
.pushNamed(EditProductScreen.routeName, arguments: {''});
}),
In the above remove 'arguments : {''}
In my case, the issue was a form i was using in two different screens, while declaring its key before the widget itself, statically. Moving the key declaration in the state solved the issue.
One of my colleague actually changed the way I've built my ListView.builder and I am not seeing the error now. I'll keep an eye on this and post any new ways to answer this question or any errors creeping up again.
I only changed the main.dart file which I have posted for reference.
main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:untitled1/addnewbranch.dart';
void main() {
runApp(
new MaterialApp(
home: new Branches(),
),
);
}
class ProjectModel {
BranchSetUpModelData branchesModel;
ProjectModel(this.branchesModel);
}
class BranchSetUpModelData {
String branchName;
String hostelType;
String area;
String city;
BranchSetUpModelData(this.branchName, this.hostelType, this.area, this.city);
}
DatabaseReference _branchesRef;
List<ProjectModel> projectModel = new List();
Map data = {};
List<String> mapKeys = new List();
DataSnapshot dataSnapshot;
class Branches extends StatefulWidget {
//const BranchView({ Key key }) : super(key: key);
const Branches({Key key}) : super(key: key);
#override
_BranchesState createState() => new _BranchesState();
}
class _BranchesState extends State<Branches> {
String userUid = '';
String text;
Future<Null> getUserUid() async {
try {
//FirebaseUser user = await FirebaseAuth.instance.currentUser();
//userUid = user.uid;
//print(userUid);
_branchesRef =
FirebaseDatabase.instance.reference().child('data').child('branches');
print('branchesref = $_branchesRef');
if (_branchesRef != null) {
try {
_branchesRef.once().then((DataSnapshot snapShot) {
dataSnapshot = snapShot;
print(snapShot is Map);
print(dataSnapshot.value);
data = dataSnapshot.value;
print(data is Map);
print(data);
data.forEach((key, value) {
mapKeys.add(key);
});
projectModel.clear();
mapKeys.forEach((value) {
_branchesRef.child(value).once().then((DataSnapshot b) {
data = b.value;
setState(() {
data.keys.forEach((k) {
BranchSetUpModelData x = new BranchSetUpModelData(
b.value['branchDetails']['branchName'],
b.value['branchDetails']['hostelType'],
b.value['branchDetails']['area'],
b.value['branchDetails']['city'],
);
print('details from for each loop');
ProjectModel projectModelData = new ProjectModel(x);
projectModel.add(projectModelData);
});
});
print('projectmodel length = ${projectModel.length}');
});
});
data.keys.forEach((k) {
print('inside this foreach loop');
print(k);
});
});
} catch (Exception) {
showDialog(
context: context,
child: new AlertDialog(
content: new Text(Exception.message.toString())));
}
} else {
print('user does not exist');
}
} catch (Exception) {
print(Exception.toString());
showDialog(
context: context,
child: new AlertDialog(
content: new Text(Exception.toString()),
));
}
}
#override
void initState() {
super.initState();
mapKeys.clear();
FirebaseDatabase.instance.setPersistenceEnabled(true);
FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000);
getUserUid();
/*setState((){
noOfBranches = mapKeys.length;
});*/
}
#override
Widget build(BuildContext context) {
//if(noOfBranches!=0) {
return new MaterialApp(
title: 'Branches',
theme: new ThemeData(
primaryColor: const Color(0xFF229E9C),
),
home: new Scaffold(
appBar: new AppBar(
title: const Text('Branches'),
backgroundColor: Colors.teal[300],
),
floatingActionButton: new FloatingActionButton(
heroTag: 'branchesHeroTag',
child: new Icon(Icons.add),
backgroundColor: Colors.teal[300],
onPressed: (() {
Navigator.push(
context,
new MaterialPageRoute(
builder: (_) => new AddNewBranch(),
),
);
}),
tooltip: 'Add Branch',
),
body: (projectModel.length == 0)
? new Center(
child: new Column(
// mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Setup your Hostel',
style: new TextStyle(
fontSize: 24.0,
color: Colors.grey[400],
fontWeight: FontWeight.bold,
),
),
new Text(
'Please click below + icon to Setup your Hostel',
style: new TextStyle(
fontSize: 16.0,
color: Colors.grey[400],
),
),
],
),
)
: new Container(
child: new ListView.builder(
padding: const EdgeInsets.only(
left: 4.0,
right: 4.0,
),
itemCount: projectModel.length,
itemBuilder: (BuildContext context, int index) {
// children: <Widget>[
return new InkWell(
onTap: (() {
/*Navigate here to a different page*/
}),
child: new Card(
child: new Column(
children: <Widget>[
new Container(
//margin: const EdgeInsets.only(top:16.0),
padding: const EdgeInsets.only(top: 16.0),
child: new Row(
children: <Widget>[
new Expanded(
child: new Row(
children: <Widget>[
new Container(
margin: const EdgeInsets.only(
left: 16.0,
right: 8.0,
top: 4.0,
bottom: 4.0),
child: new IconButton(
icon: new Icon(Icons.call),
onPressed: (() {}))),
new Container(
child: new Text(
'80/125',
style: new TextStyle(
fontSize: 18.0,
),
),
),
],
),
),
new Expanded(
child: new Row(
textDirection: TextDirection.rtl,
children: [
new Container(
margin: const EdgeInsets.only(
right: 16.0),
child: new Text(
projectModel[index]
.branchesModel
.hostelType,
style: new TextStyle(
fontSize: 18.0,
),
),
),
],
),
),
],
),
),
new Container(
margin: const EdgeInsets.fromLTRB(
16.0, 8.0, 16.0, 4.0),
child: new Row(children: <Widget>[
new Text(
projectModel[index].branchesModel.branchName,
style: new TextStyle(
fontSize: 24.0,
),
),
]),
),
new Container(
margin: const EdgeInsets.only(
left: 16.0, right: 16.0, bottom: 8.0),
child: new Row(
children: <Widget>[
new Text(
projectModel[index].branchesModel.city),
],
),
),
],
),
),
); // InkWell ends here so this has to go into ListView.builder
},
), // ListView.builder ends here.
),
),
);
}
}
I hope this will help everyone who is struggling with the same use case to solve their problem,
Many Thanks.
Mahi.

Resources