Related
My Json response status code is 200 and the object is also created but when I try to bind it with UI in ListView it doesn't show anything. I have also parsed created the model from the json data.
Here's my API_manager.dart file:
import 'package:http/http.dart' as http;
import 'package:aritic/models/contactsModel.dart';
// ignore: camel_case_types
class API_Manager {
Future<ContactsModel> getContacts() async {
var client = http.Client();
var contactsModel;
String contacts_url =
'https://exampleapi.com';
String basicAuth = 'Basic auth key example';
try {
var response = await client.get(contacts_url,
headers: <String, String>{'authorization': basicAuth});
print(response.statusCode);
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
contactsModel = contactsModel.fromJson(jsonMap);
}
} catch (Exception) {
return contactsModel;
}
return contactsModel;
}
}
My UI code:
import 'package:aritic/models/contactsModel.dart';
import 'package:aritic/services/api_manager.dart';
class ContactsPage extends StatefulWidget {
#override
_ContactsPageState createState() => _ContactsPageState();
}
class _ContactsPageState extends State<ContactsPage>
with SingleTickerProviderStateMixin {
Future<ContactsModel> _contactsModel;
bool isSearching = false;
TabController _tabController;
#override
void initState() {
// TODO: implement initState
super.initState();
_tabController = TabController(length: 2, initialIndex: 0, vsync: this);
_tabController.addListener(_handleTabIndex);
}
#override
void dispose() {
_tabController.removeListener(_handleTabIndex);
_tabController.dispose();
super.dispose();
}
void _handleTabIndex() {
setState(() {});
}
#override
Widget build(BuildContext context) {
_contactsModel = API_Manager().getContacts();
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text('Contacts'),
bottom: PreferredSize(
child: Align(
alignment: Alignment.centerLeft,
child: TabBar(
controller: _tabController,
isScrollable: true,
unselectedLabelColor: Colors.white.withOpacity(0.3),
indicatorColor: Colors.white,
tabs: [
Tab(
child: Text('Contacts'),
),
Tab(
child: Text('Companies'),
)
],
),
),
preferredSize: Size.fromHeight(40.0)),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: IconButton(
icon: Icon(Icons.search),
color: Colors.white,
onPressed: () {},
),
),
],
),
body: TabBarView(controller: _tabController, children: <Widget>[
Container(
height: double.infinity,
child: FutureBuilder<ContactsModel>(
future: _contactsModel,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
padding: const EdgeInsets.all(6),
itemCount: snapshot.data.contacts.length,
itemBuilder: (context, index) {
var contact = snapshot.data.contacts[index];
return Container(
height: 100,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(contact.owner.username,
style: TextStyle(fontSize: 16))
],
),
);
});
} else
return Center(child: CircularProgressIndicator());
})),
Container(
height: double.infinity,
child: ListView(
padding: const EdgeInsets.all(6),
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => ViewCompany()));
},
child: Container(
height: 50,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Example company',
style: TextStyle(fontSize: 16),
),
Text(
'Example company',
style: TextStyle(fontSize: 14),
)
],
),
),
),
SizedBox(
height: 5,
),
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => ViewCompany()));
},
child: Container(
height: 50,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'example',
style: TextStyle(fontSize: 16),
),
Text(
'example',
style: TextStyle(fontSize: 14),
)
],
),
),
),
],
)),
]),
floatingActionButton: _bottomButtons(),
));
}
Widget _bottomButtons() {
return _tabController.index == 0
? FloatingActionButton(
shape: StadiumBorder(),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return AddContacts();
}));
},
backgroundColor: Colors.cyan,
child: Icon(
Icons.person_add,
color: Colors.white,
))
: FloatingActionButton(
shape: StadiumBorder(),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return AddCompany();
}));
},
backgroundColor: Colors.cyan,
child: Icon(
Icons.add,
color: Colors.white,
),
);
}
}
Output Screen:
ListView should be displayed here
Dart DevTools network analysis:
response code is displayed
Json Viewer:
Contacts Json
Json sample(complete json too big to upload here):
{
"total": "187144",
"contacts": {
"897": {
"isPublished": true,
"id": 897,
"fields": {
"core": {
"points": {
"id": "47",
"label": "Points"
},
"firstname": {
"id": "2",
"label": "First Name",
"value": "Jason"
},
"lastname": {
"id": "3",
"label": "Last Name",
"value": "Lamuda"
},
"...": {
"..." : "..."
}
},
"ipAddresses": [
{
"ip": "70.127.91.131",
"ipDetails": {
"city": "Bradenton",
"region": "Florida",
"timezone": "America/New_York",
}
},
"...": {
"..." : "..."
}
The JSON has this:
{
"total": "187144",
"contacts": {
"897": {
"isPublished": true,
"id": 897,
"fields": {
So your ContactModel.contacts is a Map keyed by the id values "897" etc, not a List, so this line returns null:
var contact = snapshot.data.contacts[index];
(This should throw an exception when you reference the members of contact.) You can index into the Map like this:
List keys = snapshot.data.contacts.keys.toList();
List values = snapshot.data.contacts.values.toList();
return ListView.builder(
padding: const EdgeInsets.all(6),
itemCount: snapshot.data.contacts.length,
itemBuilder: (context, index) {
var contact = values[index];
BTW this line in API_Manager is strange:
contactsModel = contactsModel.fromJson(jsonMap);
It gives a Null pointer exception. It should of course be:
contactsModel = ContactsModel.fromJson(jsonMap);
I wanted to design a card when clicked it will navigate to a specified marker
I fetched my coordinates (markers) from cloud firestore. everything works perfectly. but when I tried to link my marker with card using pageview.builder it fails.
I already connected and fetch all the markers from firebase: firestore. the only problem I got is that I can't connect my markers.
maybe at the end of the code I used 'Future' to specify the movement of the camera wile navigating and I used it outside of pageview.builder.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
import 'package:permission/permission.dart';
class Metro extends StatefulWidget {
#override
_MetroState createState() => _MetroState();
}
String stations;
class _MetroState extends State<Metro> {
// GoogleMapController _controller;
// final CameraPosition _initialPosition = CameraPosition(target: LatLng(9.0131, 38.7240), zoom: 17.0);
LatLng _initialPosition = LatLng(9.0131, 38.7240);
GoogleMapController _controller;
Location _location= Location();
int prevPage;
PageController _pageController;
void _onMapCreated(GoogleMapController _cntrl){
_controller = _cntrl;
_location.onLocationChanged.listen((l) {
_controller.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(target: LatLng(l.latitude, l.longitude), zoom: 15)));
});
}
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
void initMarker(specify, specifyId) async {
var markerIdVal = specifyId;
final MarkerId markerId = MarkerId(markerIdVal);
final Marker marker = Marker(
markerId: markerId,
draggable: false,
position:
LatLng(specify['Location'].latitude, specify['Location'].longitude),
infoWindow: InfoWindow(title: specify['Name'], snippet: 'Station'),
);
setState(() {
markers[markerId] = marker;
},
);
_pageController = PageController(initialPage: 0, viewportFraction: 0.8)..addListener(_onScroll);
}
void _onScroll() {
if (_pageController.page.toInt() != prevPage) {
prevPage = _pageController.page.toInt();
moveCamera();
}
}
getMarkerData() async {
Firestore.instance.collection('route 1 markers').getDocuments().then((myMockDoc) {
if (myMockDoc.documents.isNotEmpty) {
for (int i = 0; i < myMockDoc.documents.length; i++) {
initMarker(myMockDoc.documents[i].data, myMockDoc.documents[i].documentID);
}
}
}
);
}
#override
void initState() { enter code here
getMarkerData();
super.initState();
}
#override
Widget build(BuildContext context) {
Set<Marker> getMarker() {
return <Marker>[
Marker(
markerId: MarkerId('Station'),
position: _initialPosition,
icon: BitmapDescriptor.defaultMarker,
infoWindow: InfoWindow(title: 'Home'))
].toSet();
}
return Scaffold(
// floatingActionButton: FloatingActionButton(
// onPressed: (){},
// backgroundColor: Colors.lightGreen,
// child: Icon(Icons.search),
// ),
body: Stack(
children: [
GoogleMap(
markers: Set<Marker>.of(markers.values),
mapType: MapType.normal,
initialCameraPosition: CameraPosition(target: _initialPosition, zoom: 25),
onMapCreated: _onMapCreated,
myLocationEnabled: true,
myLocationButtonEnabled: true,
mapToolbarEnabled: false,
),
Positioned(
bottom: 20.0,
child: Container(
height: 200,
width: MediaQuery.of(context).size.width,
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('route 1 markers').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return PageView.builder( // Changes begin here
controller: _pageController,
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
final document = snapshot.data.documents[index];
return AnimatedBuilder(
animation: _pageController,
builder: (BuildContext context, Widget widget){
double value = 1;
if (_pageController.position.haveDimensions) {
value = _pageController.page - index;
value = (1 - (value.abs() * 0.3) + 0.06).clamp(0.0, 1.0);
}
return Center(
child: SizedBox(
height: Curves.easeInOut.transform(value) * 125.0,
width: Curves.easeInOut.transform(value) * 350.0,
child: widget,
),
);
},
child: InkWell(
onTap: (){moveCamera();},
child: Stack(
children: [
Center(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 20.0
),
height: 125,
width: 270,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.black54,
offset: Offset(0.0, 4.0),
blurRadius: 10.0,
),
]),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white
),
child: Row(
children: [
Container(
height: 90,
width: 90,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10.0),
topLeft: Radius.circular(10.0)),
image: DecorationImage(
image: NetworkImage(
document['img']),
fit: BoxFit.cover))),
SizedBox(width: 5.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
document['Name'],
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold),
),
Positioned(
bottom: 5.0,
child: Text(
"Addis Ababa, Ethiopia",
style: TextStyle(
fontSize: 13.0,
fontWeight: FontWeight.w600),
),
),
Container(
width: 170,
child: Text(
document['Detail'],
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w300),
),
),
],
)
],
),
),
),
)
],
),
),
);
}
);
}
},
),
))
],
),
);
}
Future<void> moveCamera() async{
_controller.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: document[_pageController.page.toInt()].Location,
zoom: 14.0,
tilt: 45.0,
bearing: 45.0,
)));
}
}
SO I need your help, help me out please. I posted my code
I use the following code to generate 10 predefined cards on a flutter screen which doesn't change:
List cards = new List.generate(10, (i)=>new QuestionCard()).toList();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('My First App'),
backgroundColor:new Color(0xFF673AB7),
),
body: new Container(
child: new ListView(
children: cards,
)
)
);
}
}
class QuestionCard extends StatefulWidget {
#override
_QuestionCardState createState() => _QuestionCardState();
}
class _QuestionCardState extends State<QuestionCard> {
#override
Widget build(BuildContext context) {
return Container(
child: Card(
borderOnForeground: true,
color: Colors.green,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
trailing: Icon(Icons.album),
title: Text('Q1'),
subtitle: Text('What is the name of this location?'),
),
new TextFormField(
decoration: new InputDecoration(
labelText: "Answer Question",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Type your answer here";
}else{
return null;
}
},
keyboardType: TextInputType.text,
style: new TextStyle(
fontFamily: "Poppins",
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Save'),
onPressed: () {/* ... */},
),
],
),
],
),
),
);
}
}
My json is simple (questions.json):
{
"Questions":
[
{
"id" : 1,
"quest" : ["question one"]
},
{
"id" : 2,
"quest" : ["question two", "question three"]
},
{
"id" : 3,
"quest" : ["question four"]
},
{
"id" : 4,
"quest" : ["question five", "question six", "question seven"]
}
]
}
So I have 2 questions I need to solve:
1. If I have more than 1 question I'll need to add an additional text box for a response for which I'll use a different card type, 2, 3, 4 max, which I'll need to define once.
But my real question here:
How do I generate the list based on the json response:
Future _loadQuestionAssets() async
{
return await rootBundle.loadString('assets/questions.json');
}
Future loadQuestion() async{
String jsonString = await _loadQuestionAssets();
final jsonResponse = json.decode(jsonString);
Questions question = new Questions.fromJson(jsonResponse);
//List cards = new List.generate(length, generator)
}
try this:
class MyFirstApp extends StatefulWidget{
#override
createState()=> new _appState();
}
class _appState extends State<MyFirstApp>{
List _displayData;
//assuming that you saved your json file in your assets folder
loadJson() async {
String data = await rootBundle.loadString('assets/json/questions.json');
jsonResult = json.decode(data);
print(jsonResult);
setState((){
_displayData = jsonResult["Questions"];
});
}
#override
void initState(){
super.initState();
loadJson();
}
#override
Widget build(BuildContext context){
return Scaffold(
appbar: Appbar(
title: Text("My APP")
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: _displayData == null ? Center(child: CircularProgressIndicator()) :
ListView.builder(
itemcount: _displayData.length,
itembuilder: (context, index){
return Container(
width: MediaQuery.of(context).size.width,
height: 80,
margin: EdgeInsets.only(bottom: 5),
child: Text(_displayData[index]["id"])
);
}
)
)
);
}
}
I want to put a marker on the map and when I put marker it will get that address and filled into the textbox.
like I've mentioned in this images when I put a marker and then click on show address it will take that address and filled into textboxes. Hope you understand the question. if any query then let me know. I need help please help me. because I am very much stuck in this problem.
Here is some code for google maps.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:tudo/src/styles/colors.dart';
import 'package:tudo/src/utils/navigation_helper.dart';
import 'package:tudo/src/widgets/google_map.dart';
const kGoogleApiKey = "API_KEY";
class BspAddressmapscreen extends StatefulWidget {
BspAddressmapscreen({Key key}) : super(key: key);
#override
_BspAddressmapscreenState createState() => _BspAddressmapscreenState();
}
class _BspAddressmapscreenState extends State<BspAddressmapscreen> {
final homeScaffoldKey = GlobalKey<ScaffoldState>();
Completer<GoogleMapController> _controller = Completer();
#override
void initState() {
super.initState();
}
double zoomVal = 5.0;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
NavigationHelper.navigatetoBack(context);
}),
centerTitle: true,
title: Text("Business Address Detail"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
bottomNavigationBar: Container(
color: Colors.transparent,
height: 56,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.arrow_back_ios),
label: Text('Show Address'),
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BspAddressmapscreen()));
},
),
],
),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: Stack(
children: <Widget>[
_searchbar(),
_buildGoogleMap(context),
_zoomminusfunction(),
_zoomplusfunction(),
],
),
),
);
}
Widget _zoomminusfunction() {
return Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: Icon(FontAwesomeIcons.searchMinus, color: Color(0xff008080)),
onPressed: () {
zoomVal--;
_minus(zoomVal);
}),
);
}
Widget _zoomplusfunction() {
return Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(FontAwesomeIcons.searchPlus, color: Color(0xff008080)),
onPressed: () {
zoomVal++;
_plus(zoomVal);
}),
);
}
Future<void> _minus(double zoomVal) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: zoomVal)));
}
Future<void> _plus(double zoomVal) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: zoomVal)));
}
Widget _buildGoogleMap(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: GoogleMap(
mapType: MapType.normal,
initialCameraPosition:
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
);
}
Widget _searchbar() {
return Positioned(
top: 50.0,
right: 15.0,
left: 15.0,
child: Container(
height: 50.0,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), color: Colors.white),
child: TextField(
decoration: InputDecoration(
hintText: 'Enter Address',
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 15.0, top: 15.0),
suffixIcon: IconButton(
icon: Icon(Icons.search),
//onPressed: searchandNavigate,
onPressed: () {},
iconSize: 30.0)),
onChanged: (val) {
setState(() {
// searchAddr = val;
});
},
),
),
);
}
}
Use below code to plot marker and get an address on button click, also use geocoder to get the address from latlng
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geocoder/geocoder.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
const kGoogleApiKey = "API_KEY";
class BspAddressmapscreen extends StatefulWidget {
BspAddressmapscreen({Key key}) : super(key: key);
#override
_BspAddressmapscreenState createState() => _BspAddressmapscreenState();
}
class _BspAddressmapscreenState extends State<BspAddressmapscreen> {
final homeScaffoldKey = GlobalKey<ScaffoldState>();
Completer<GoogleMapController> _controller = Completer();
#override
void initState() {
super.initState();
}
double zoomVal = 5.0;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
/*NavigationHelper.navigatetoBack(context);*/
}),
centerTitle: true,
title: Text("Business Address Detail"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
bottomNavigationBar: Container(
color: Colors.transparent,
height: 56,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.arrow_back_ios),
label: Text('Show Address'),
textColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
getUserLocation();
},
),
],
),
),
body: Container(
height: double.infinity,
width: double.infinity,
child: Stack(
children: <Widget>[
_searchbar(),
_buildGoogleMap(context),
_zoomminusfunction(),
_zoomplusfunction(),
],
),
),
);
}
getUserLocation() async {
markers.values.forEach((value) async {
print(value.position);
// From coordinates
final coordinates =
new Coordinates(value.position.latitude, value.position.longitude);
var addresses = await Geocoder.google(kGoogleApiKey)
.findAddressesFromCoordinates(coordinates);
print("Address: ${addresses.first.featureName}");
});
}
Widget _zoomminusfunction() {
return Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: Icon(Icons.remove, color: Color(0xff008080)),
onPressed: () {
zoomVal--;
_minus(zoomVal);
}),
);
}
Widget _zoomplusfunction() {
return Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(Icons.add, color: Color(0xff008080)),
onPressed: () {
zoomVal++;
_plus(zoomVal);
}),
);
}
Future<void> _minus(double zoomVal) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: zoomVal)));
}
Future<void> _plus(double zoomVal) async {
final GoogleMapController controller = await _controller.future;
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: zoomVal)));
}
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
Widget _buildGoogleMap(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: GoogleMap(
mapType: MapType.normal,
initialCameraPosition:
CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
markers: Set<Marker>.of(markers.values),
onLongPress: (LatLng latLng) {
// creating a new MARKER
final MarkerId markerId = MarkerId('4544');
final Marker marker = Marker(
markerId: markerId,
position: latLng,
);
setState(() {
markers.clear();
// adding a new marker to map
markers[markerId] = marker;
});
},
),
);
}
Widget _searchbar() {
return Positioned(
top: 50.0,
right: 15.0,
left: 15.0,
child: Container(
height: 50.0,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), color: Colors.white),
child: TextField(
decoration: InputDecoration(
hintText: 'Enter Address',
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 15.0, top: 15.0),
suffixIcon: IconButton(
icon: Icon(Icons.search),
//onPressed: searchandNavigate,
onPressed: () {},
iconSize: 30.0,
),
),
onChanged: (val) {
setState(() {
// searchAddr = val;
});
},
),
),
);
}
}
I have a problem to make UI in flutter still update in realtime, I got the data from JSON web, made by node JS and MySQL.
Here my UI looks like. Image Shown null
I don't know why it happens. at first, navigate to that page it appears null, then I back to the previous page and do the same way, and it works the data appears. Image shows Data
My question is how to make the data always update in realtime?
here my code
import 'package:crophero/detail.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:crophero/home_page.dart';
import 'package:crophero/login_page.dart';
import 'package:crophero/api_provider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
import 'dart:io';
class SensorPage extends StatefulWidget {
SensorPage({Key key, this.id, this.gh, this.idgh, this.namagh})
: super(key: key);
final int id;
final int idgh;
final String namagh;
final List gh;
static String tag = 'sensor-page';
#override
_SensorPageState createState() => new _SensorPageState();
}
Timer timer;
int suhu;
int rh;
int cahaya;
int air;
int tanah;
int angin;
class _SensorPageState extends State<SensorPage> {
Future loadSensor() async {
var jsonString = await http
.get('$endPoint/data_realtime?user_id=$id&&gh_id=${widget.idgh}');
final jsonResponse = json.decode(jsonString.body);
setState(() {
suhu = jsonResponse['suhu'];
rh = jsonResponse['rh'];
cahaya = jsonResponse['cahaya'];
air = jsonResponse['air'];
tanah = jsonResponse['tanah'];
angin = jsonResponse['angin'];
});
}
#override
void initState() {
super.initState();
loadSensor();
_buatlist();
}
#override
void dispose() {
super.dispose();
timer.cancel();
}
List<Container> daftarSensor = new List();
var karakter = [
{
"nama": "Air Temperature",
"gambar": "temp.png",
"warna": 0xFFD50000,
"nilai": "$suhu *C"
},
{
"nama": "Relative Humidity",
"gambar": "rh.png",
"warna": 0xFF33691E,
"nilai": "$rh %"
},
{
"nama": "Water Temperature",
"gambar": "water.png",
"warna": 0xFF0288D1,
"nilai": "$air *C"
},
{
"nama": "Light Intensity",
"gambar": "light.png",
"warna": 0xFFFFAB00,
"nilai": "${cahaya} lux"
},
{
"nama": "Soil Moisture",
"gambar": "soil.png",
"warna": 0xFF795548,
"nilai": "$tanah"
},
{
"nama": "Wind Velocity",
"gambar": "wind.png",
"warna": 0xFF00695C,
"nilai": "${angin} m/s"
},
];
_buatlist() async {
for (var i = 0; i < karakter.length; i++) {
final karakternya = karakter[i];
final data = karakter[i];
final String gambar = karakternya["gambar"];
daftarSensor.add(
new Container(
padding: new EdgeInsets.all(10.0),
child: new Column(
children: <Widget>[
new Material(
child: new Column(
children: <Widget>[
MaterialButton(
minWidth: 200.0,
height: 75.0,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Detail(
gambar: karakternya["gambar"],
warna: karakternya["warna"],
nilai: data["nilai"],
nama: karakternya["nama"],
idgh: widget.idgh,
namagh: widget.namagh,
)));
},
child: Column(
children: <Widget>[
Row(
children: <Widget>[
new Image.asset(
"img/$gambar",
fit: BoxFit.cover,
width: 50,
),
SizedBox(width: 130),
Text((karakternya["nilai"]),
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
textAlign: TextAlign.left),
],
),
Text((karakternya["nama"]),
style: TextStyle(
color: Colors.white,
fontSize: 14,
),
textAlign: TextAlign.end),
],
),
)
],
),
color: Color(karakternya["warna"]),
borderRadius: BorderRadius.circular(20),
),
],
),
),
);
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
bottomNavigationBar: Container(
height: 50,
child: BottomAppBar(
color: Colors.green[900],
child: new Center(
child: new Row(
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(horizontal: 50.0),
),
],
),
),
),
),
backgroundColor: Colors.white,
appBar: new AppBar(
backgroundColor: Colors.green[900],
title: new Text(
"${widget.namagh} ",
style: new TextStyle(color: Colors.white),
),
),
body: new ListView(
children: daftarSensor,
),
);
}
}
It's showing null because the states not updated yet. Once you re-enter this page, it calls build() and will apply updated state(which is previously assigned from loadSensor()), so it's showing correctly.
What I noticed from your code, there is no guarantee that _buatlist() will be called after loadSensor(). Since _buatlist() is expecting to see newly updated value from loadSensor(), they should work asynchronously.
So try put daftarSensor to your state group, and once new items loaded from loadSensor(), call _buatlist() to build dafterSensor and also call setState inside of _buatlist(), then it will update ListView.