Google maps flutter user location - google-maps

it does not even show the request for permission to access the users location
enter image description here
i am working on a sort of a delivery application but for good upon request just like uber, the code below is to access the users location upon loading .The problem is the code does not show any errors but does not show google maps after loading it just shows white background.
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:isntadelivery/Signin.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart' as Thendelo;
import 'package:fluttertoast/fluttertoast.dart';
import 'package:permission_handler/permission_handler.dart';
// import 'package';
class Homepage extends StatefulWidget {
Homepage({Key key}) : super(key: key);
#override
_HomepageState createState() => _HomepageState();
}
class _HomepageState extends State<Homepage> {
GoogleMapController _controller;
GoogleMapController mapController;
Position position;
Widget _child;
Future<void> getpermission() async {
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.location);
if (permission == PermissionStatus.denied) {
await PermissionHandler()
.requestPermissions([PermissionGroup.locationAlways]);
}
var geolocater = new Geolocator();
GeolocationStatus geolocationStatus =
await geolocater.checkGeolocationPermissionStatus();
switch (geolocationStatus) {
case GeolocationStatus.denied:
showToast('denied');
break;
case GeolocationStatus.disabled:
showToast('disabled');
break;
case GeolocationStatus.restricted:
showToast('restricted');
break;
case GeolocationStatus.unknown:
showToast('unknown');
break;
case GeolocationStatus.granted:
showToast('Access granted');
_getCurrentLocation();
}
}
Set<Marker> _createMarker() {
return <Marker>[
Marker(
markerId: MarkerId('home'),
position: LatLng(position.latitude, position.longitude),
icon: BitmapDescriptor.defaultMarker,
infoWindow: InfoWindow(title: 'Current Location'))
].toSet();
}
void showToast(message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
// timeInSecFor Ios: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
void _setStyle(GoogleMapController controller) async {
String value = await DefaultAssetBundle.of(context)
.loadString('assets/map_style.json');
controller.setMapStyle(value);
}
Widget _mapWidget() {
return GoogleMap(
mapType: MapType.normal,
markers: _createMarker(),
initialCameraPosition: CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: 12.0,
),
onMapCreated: (GoogleMapController controller) {
_controller = controller;
// _controller.complete(controller);
_setStyle(controller);
},
);
}
//map style variable
void _getCurrentLocation() async {
Position res = await Geolocator().getCurrentPosition();
setState(() {
position = res;
_child = _mapWidget();
});
}
// singoutmethod
signOutGoogle() async {
await googleSignIn.signOut();
print("User Sign Out");
}
// firebase authorisation
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: _child,
drawer: Drawer(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: new Text('Thabelo Mutshinyani'),
accountEmail: new Text('mutshinyanit#gmail.com'),
currentAccountPicture: new CircleAvatar(),
),
ListTile(
leading: Icon(Icons.person_outline),
title: Text('Update Profile'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.payment),
title: Text('payment details'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.exit_to_app),
title: Text('LogOut'),
onTap: () {
signOutGoogle().whenComplete(() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return Signin();
},
),
);
});
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
);
}
}

I think, based on your code, you should add the desiredAccuracy inside your _getCurrentLocation(). Like this:
void _getCurrentLocation() async {
Position res = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
setState(() {
position = res;
_child = _mapWidget();
});
}
And, to run the _getCurrentLocation() function at the beginning of the app, you should wrap it inside the initState method.
Inside your StatefulWidget class, add:
#override
void initState() {
_getCurrentLocation();
super.initState();
}
And then add the Location permission inside the device or emulator you're using. Add this line of codes inside the AndroidManifest.xml file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And my tips, cold restart your app (stop debug and debug it again from the beginning).

For IOS If you using this plugin, you also need to add permission in info plist like this, just copy and paste it.
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location when in use</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Always and when in use!</string>
<key>NSLocationUsageDescription</key>
<string>Older devices need location.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Can I have location always?</string>
For android
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

#override
void initState() {
_getCurrentLocation();
super.initState();
}

Related

how to get a data from HtmlElementView in flutter-web

i am having a trouble with adding webview in side flutter web
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'dart:ui' as ui;
import 'dart:html' as html;
class UserAddress3 extends StatefulWidget {
const UserAddress3({Key? key}) : super(key: key);
#override
State<UserAddress3> createState() => _UserAddress3State();
}
class _UserAddress3State extends State<UserAddress3> {
#override
void initState() {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'html.iframeElement',
(int viewId) => html.IFrameElement()
..src = 'https://daum_postcode_mobile'
..style.width = '100%'
..style.height = '100%'
..style.border = 'none');
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('주소 검색'),
backgroundColor: Colors.white,
),
body: Container(
child: HtmlElementView(
viewType: 'html.iframeElement',
),
),
);
}
}
'https://daum_postcode_mobile' this link leads to where we can find a address
so the web-view displays fine but i can't have a datas if I click the address
I thought it would work as same as how Webview worked in Flutter App but it seems totaly different...
Is there any one knows how to get datas from HtmleElementView???
p.s and this is my codes which used in my app
class KakaoAddress extends StatefulWidget {
#override
_KakaoAddressState createState() => _KakaoAddressState();
}
class _KakaoAddressState extends State<KakaoAddress> {
final Completer<WebViewController> _controller = Completer<WebViewController>();
#override
Widget build(context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black,
),
titleSpacing: 0.0,
elevation: 0.0,
title: const Text(
'주소 검색',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Colors.black),
),
actions: <Widget>[
SampleMenu(),
],
backgroundColor: Colors.white,
),
body: Builder(builder: (context) {
return WebView(
initialUrl: 'https://daum_postcode_mobile',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
// ignore: prefer_collection_literals
javascriptChannels: <JavascriptChannel>[
_toasterJavascriptChannel(context),
].toSet(),
);
}),
);
}
JavascriptChannel _toasterJavascriptChannel(context) {
return JavascriptChannel(
name: 'Daum',
onMessageReceived: (JavascriptMessage message) async {
final myJsonAsString = message.message;
dynamic received = json.decode(myJsonAsString);
dynamic address = received["address"];
Navigator.pop(context, address);
});
}
}
class SampleMenu extends StatelessWidget {
#override
Widget build(context) {
return FutureBuilder<WebViewController>(
builder: (context, AsyncSnapshot<WebViewController> controller) {
return IconButton(
icon: Icon(
Icons.close,
size: 25.0,
),
onPressed: () {
Navigator.pop(context);
});
},
);
}
}
I made something similar, which may help you. I handled mouse clicks performed inside HtmlElementView, with Dart code, the following way:
In the code passed to ui.platformViewRegistry.registerViewFactory() I used DOM manipulation to attach a listener to the onClick event of an element.
You can do the same with a custom event and trigger that event anytime from Javascript to call and pass data to the Dart side.

Flutter Google Maps: How can you change maptype after runtime?

I am trying to change from normal to satellite when pressing a button as shown below, but i get an error that setMapType does not exist.
mapController.setMapType(MapType.satellite);
Anyone knows what I am doing wrong?
Create a MapType variable:
MapType _currentMapType = MapType.normal;
Reference this variable when calling your Google Map widget:
googleMap = new GoogleMap(
mapType: _currentMapType,
//etc
Create a floating button widget to toggle map types:
floatingActionButton: FloatingActionButton(
child: Icon(Icons.layers),
onPressed: ()=>
{
setState(() {
_currentMapType = (_currentMapType == MapType.normal) ? MapType.satellite : MapType.normal;
});
},
heroTag: null,
),
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:search_map_place/search_map_place.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
String apiKEY;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Search Map Place Demo',
home: MapSample(),
);
}
}
class MapSample extends StatefulWidget {
#override
State<MapSample> createState() => MapSampleState();
}
class MapSampleState extends State<MapSample> {
Completer<GoogleMapController> _mapController = Completer();
final CameraPosition _initialCamera = CameraPosition(
target: LatLng(-20.3000, -40.2990),
zoom: 14.0000,
);
var maptype = MapType.normal;
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Stack(
children: <Widget>[
GoogleMap(
mapType: maptype,
initialCameraPosition: _initialCamera,
onMapCreated: (GoogleMapController controller) {
_mapController.complete(controller);
},
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
child: const Icon(Icons.my_location),
onPressed: () {
setState(() {
this.maptype=MapType.satellite;
});
},
),
);
}
}

How to add marker in the google map using flutter?

I am creating a nearby flutter app which shows restaurant around your location. i have found the nearby location but unable to add markers on the nearby coordinates.I want to know how to add markers to my location using google API and how to load the location from the list to my map.
void getData() async {
http.Response response = await http.get(
'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=1500&type=restaurant&key=API_KEY');
if (response.statusCode == 200) {
String data = response.body;
var decodedData = jsonDecode(data);
print(decodedData);
List<String> names = [];
List<double> lat = [];
List<double> lng = [];
for (var i = 0; i < 10; i++) {
names.add(decodedData['results'][i]['name']);
lat.add(decodedData['results'][i]['geometry']['location']['lat']);
lng.add(decodedData['results'][i]['geometry']['location']['lng']);
}
print(names);
print(lat);
print(lng);
}
}
Expanded(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(-33.8670522, 151.1957362),
zoom: 14.4746,
),
markers: Set<Marker>.of(markers.values),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
),
),
Make sure you add your API_KEY. A working example of your requirement follows
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
LatLng latlng = LatLng(
-33.8670522,
151.1957362,
);
Iterable markers = [];
#override
void initState() {
super.initState();
getData();
}
getData() async {
try {
final response =
await http.get('https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=1500&type=restaurant&key=API_KEY');
final int statusCode = response.statusCode;
if (statusCode == 201 || statusCode == 200) {
Map responseBody = json.decode(response.body);
List results = responseBody["results"];
Iterable _markers = Iterable.generate(10, (index) {
Map result = results[index];
Map location = result["geometry"]["location"];
LatLng latLngMarker = LatLng(location["lat"], location["lng"]);
return Marker(markerId: MarkerId("marker$index"),position: latLngMarker);
});
setState(() {
markers = _markers;
});
} else {
throw Exception('Error');
}
} catch(e) {
print(e.toString());
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GoogleMap(
markers: Set.from(
markers,
),
initialCameraPosition: CameraPosition(target: latlng, zoom: 15.0),
mapType: MapType.hybrid,
onMapCreated: (GoogleMapController controller) {},
),
);
}
}
In the end you have to structure it yourself but it should look something like this
final Set<Marker> _markers = {};
setState(() {
// add marker on the position
_markers.add(Marker(
// This marker id can be anything that uniquely identifies each marker.
markerId: MarkerId(_lastMapPosition.toString()),
position: _lastMapPosition,
infoWindow: InfoWindow(
// title is the address
title: address.addressLine,
// snippet are the coordinates of the position
snippet: 'Lat: ${address.coordinates.latitude}, Lng: ${address
.coordinates.longitude}',
),
icon: BitmapDescriptor.defaultMarker,
));
}
Iterable markers = [];
// in GoogleMap use like this
GoogleMap(...
markers: Set.from(markers),
),
// in function or where you want
Iterable _markers = Iterable.generate(list.length, (index) {
return Marker(
markerId: MarkerId("marker$index"),
position: list[index].position);
});
setState(() {
markers = _markers;
});

Flutter Google Maps not determining current location of device

I'm using Flutter's Geolocator and Google Maps packages to determine a device's location. I utilize the Circular Progress Bar to wait for the current location to be determined. Once determined, Google Maps loads with the device's location identified.
When the application loads, the circular progress bar is displayed but the map is not loaded despite the notification being displayed and accepted to use location services; the app hangs on the circular progress bar. I don't believe this to be an API issue as I have had success loading the map with coordinates specified in InitialCameraPosition.
Is the device's location not being determined which is the cause for the map to not load with the location indicated?
I've tried running the app on both Android emulator and a physical device without success.
Android Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="smartkart.app.com.coffee">
<!-- io.flutter.app.FlutterApplication is an android.app.Application
that
calls FlutterMain.startInitialization(this); in its onCreate
method.
In most cases you can leave this as-is, but you if you want to
provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:name="io.flutter.app.FlutterApplication"
android:label="coffee"
android:icon="#mipmap/ic_launcher">
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="API KEY HERE"/>
<activity../>
Maps Screen
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class FirstScreen extends StatefulWidget {
const FirstScreen({Key key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreen();
}
class _FirstScreen extends State<FirstScreen> {
GoogleMapController mapController;
var currentLocation;
#override
void initState(){
super.initState();
Geolocator().getCurrentPosition().then((currloc){
currentLocation = currloc;
});
}
#override
Widget build(BuildContext context) {
return currentLocation == null ? Container(
alignment: Alignment.center,
child: Center(
child: CircularProgressIndicator(),
),
):
Stack(
children: <Widget>[
GoogleMap(
initialCameraPosition:
CameraPosition(target: LatLng(currentLocation.latitude,
currentLocation.longitude), zoom: 10),
onMapCreated: _onMapCreated,
myLocationEnabled: true,
mapType: MapType.normal,
),
],
);
}
void _onMapCreated(GoogleMapController controller) {
setState(() {
mapController = controller;
});
}
}
I expect the notification to use location services to appear while the circular progress bar is displayed. Once the location is determined, the InitialCameraPosition displays the device's location on the map.
Try the following code as a solution. You can modify the map widget to your use case:
import 'package:flutter/cupertino.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<Map> {
Completer<GoogleMapController> controller1;
//static LatLng _center = LatLng(-15.4630239974464, 28.363397732282127);
static LatLng _initialPosition;
final Set<Marker> _markers = {};
static LatLng _lastMapPosition = _initialPosition;
#override
void initState() {
super.initState();
_getUserLocation();
}
void _getUserLocation() async {
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
List<Placemark> placemark = await Geolocator().placemarkFromCoordinates(position.latitude, position.longitude);
setState(() {
_initialPosition = LatLng(position.latitude, position.longitude);
print('${placemark[0].name}');
});
}
_onMapCreated(GoogleMapController controller) {
setState(() {
controller1.complete(controller);
});
}
MapType _currentMapType = MapType.normal;
void _onMapTypeButtonPressed() {
setState(() {
_currentMapType = _currentMapType == MapType.normal
? MapType.satellite
: MapType.normal;
});
}
_onCameraMove(CameraPosition position) {
_lastMapPosition = position.target;
}
_onAddMarkerButtonPressed() {
setState(() {
_markers.add(
Marker(
markerId: MarkerId(_lastMapPosition.toString()),
position: _lastMapPosition,
infoWindow: InfoWindow(
title: "Pizza Parlour",
snippet: "This is a snippet",
onTap: (){
}
),
onTap: (){
},
icon: BitmapDescriptor.defaultMarker));
});
}
Widget mapButton(Function function, Icon icon, Color color) {
return RawMaterialButton(
onPressed: function,
child: icon,
shape: new CircleBorder(),
elevation: 2.0,
fillColor: color,
padding: const EdgeInsets.all(7.0),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _initialPosition == null ? Container(child: Center(child:Text('loading map..', style: TextStyle(fontFamily: 'Avenir-Medium', color: Colors.grey[400]),),),) : Container(
child: Stack(children: <Widget>[
GoogleMap(
markers: _markers,
mapType: _currentMapType,
initialCameraPosition: CameraPosition(
target: _initialPosition,
zoom: 14.4746,
),
onMapCreated: _onMapCreated,
zoomGesturesEnabled: true,
onCameraMove: _onCameraMove,
myLocationEnabled: true,
compassEnabled: true,
myLocationButtonEnabled: false,
),
Align(
alignment: Alignment.topRight,
child: Container(
margin: EdgeInsets.fromLTRB(0.0, 50.0, 0.0, 0.0),
child: Column(
children: <Widget>[
mapButton(_onAddMarkerButtonPressed,
Icon(
Icons.add_location
), Colors.blue),
mapButton(
_onMapTypeButtonPressed,
Icon(
IconData(0xf473,
fontFamily: CupertinoIcons.iconFont,
fontPackage: CupertinoIcons.iconFontPackage),
),
Colors.green),
],
)),
)
]),
),
);
}
}
You seem to be missing setState in your initState.
It should look like this:
#override
void initState(){
super.initState();
Geolocator().getCurrentPosition().then((currloc){
setState((){
currentLocation = currloc;
});
});
}
Use GeoLocator package with google_maps_flutter
Sample Code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class MapScreen extends StatefulWidget {
#override
State<MapScreen> createState() => MapScreenState();
}
class MapScreenState extends State<MapScreen> {
LatLng initPosition = LatLng(0, 0); //initial Position cannot assign null values
LatLng currentLatLng= LatLng(0.0, 0.0); //initial currentPosition values cannot assign null values
LocationPermission permission = LocationPermission.denied; //initial permission status
Completer<GoogleMapController> _controller = Completer();
#override
void initState() {
super.initState();
getCurrentLocation();
checkPermission();
}
//checkPersion before initialize the map
void checkPermission() async{
permission = await Geolocator.checkPermission();
}
// get current location
void getCurrentLocation() async{
await Geolocator.getCurrentPosition().then((currLocation) {
setState(() {
currentLatLng =
new LatLng(currLocation.latitude, currLocation.longitude);
});
});
}
//call this onPress floating action button
void _currentLocation() async {
final GoogleMapController controller = await _controller.future;
getCurrentLocation();
controller.animateCamera(CameraUpdate.newCameraPosition(
CameraPosition(
bearing: 0,
target: currentLatLng,
zoom: 18.0,
),
));
}
//Check permission status and currentPosition before render the map
bool checkReady(LatLng? x, LocationPermission? y) {
if (x == initPosition || y == LocationPermission.denied || y == LocationPermission.deniedForever) {
return true;
} else {
return false;
}
}
#override
Widget build(BuildContext context) {
print(permission);
print("Current Location --------> " +
currentLatLng.latitude.toString() +
" " +
currentLatLng.longitude.toString());
return MaterialApp(
//remove debug banner on top right corner
debugShowCheckedModeBanner: false,
home: new Scaffold(
//ternary operator use for conditional rendering
body: checkReady(currentLatLng, permission)
? Center(child: CircularProgressIndicator())
//Stack : place floating action button on top of the map
: Stack(children: [
GoogleMap(
myLocationEnabled: true,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
mapType: MapType.normal,
initialCameraPosition: CameraPosition(target: currentLatLng),
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
//Positioned : use to place button bottom right corner
Positioned(
bottom: 0,
right: 0,
child: Container(
margin: EdgeInsets.all(15),
child: FloatingActionButton(
onPressed: _currentLocation,
child: Icon(Icons.location_on)),
),
),
]),
),
);
}
}

How to parse JSON only once in Flutter

I am making an app which takes values through JSON parsing. My app has multiple tabs but each time im swiping between tabs, the JSON sends a new read request every time. Below is my code:
Home.dart (Holds the navigation tab)
import 'package:flutter/material.dart';
import './First.dart' as first;
import './Second.dart' as second;
import './Third.dart' as third;
import './Fourth.dart' as fourth;
import './Fifth.dart' as fifth;
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
final List<NewPage> _tabs = [
new NewPage(title: "Providers Near Me",color: Colors.blue[500]),
new NewPage(title: "Providers Search",color: Colors.blueGrey[500]),
new NewPage(title: "Providers List",color: Colors.teal[500]),
new NewPage(title: "My Info",color: Colors.indigo[500]),
new NewPage(title: "My Dependents Info",color: Colors.red[500]),
];
NewPage _myHandler;
TabController tabController;
String pos = 'top';
void initState(){
super.initState();
tabController = new TabController(length: 5, vsync: this);
_myHandler = _tabs[0];
tabController.addListener(_handleSelected);
}
void _handleSelected() {
setState(() {
_myHandler = _tabs[tabController.index];
});
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
///
/// This method defines the different tabs in the Tab Bar. This is the
/// constructor for the Navigation Bar that will be used by the user most.
///
TabBar navbar (){
return TabBar(
controller: tabController,
tabs: <Widget>[
new Tab(
icon: new Icon(Icons.healing),
),
new Tab(
icon: new Icon(Icons.search),
),
new Tab(
icon: new Icon(Icons.list),
),
new Tab(
icon: new Icon(Icons.person),
),
new Tab(
icon: new Icon(Icons.group),
),
],
);
}
///
/// This method returns the App Bar properties. Its takes in an argument to
/// determining if the Tab Bar should be at the top or at the bottom of the
/// screen. If the Tab Bar is to be at the top of the screen, it will return
/// the AppBar with the bottom property. If the Tab Bar is to be at the
/// bottom, it will return the AppBar without the bottom property
///
AppBar barController(String position){
if (position == 'top'){
return AppBar(
title: new Text(_myHandler.title),
backgroundColor: _myHandler.color,
bottom: navbar(),
);
}
else if (position == 'bottom'){
return AppBar(
title: new Text(_myHandler.title),
backgroundColor: _myHandler.color,
);
}
else{
return null;
}
}
///
/// This method controls the Navigation Bar at the bottom of the page. If the
/// navigation bar is to be displayed at the bottom, then the navigation bar
/// will be returned. Else, null will be returned.
///
Material bottomBarController(String disp){
if (disp == 'bottom'){
return Material(
color: _myHandler.color,
child: navbar(),
);
}
else{
return null;
}
}
#override
Widget build(BuildContext context){
return new Scaffold(
endDrawer: new AppDrawer(),
appBar: barController(pos),
body: new TabBarView(
children: <Widget>[
new first.First(),
new second.MapPage(),
new third.Third(),
new fourth.Fourth(),
new fifth.Fifth(),
],
controller: tabController,
),
bottomNavigationBar: bottomBarController(pos)
);
}
}
// Appdrawer
// This method opens a drawer where more settings are available to control
// according to user needs.
class AppDrawer extends StatefulWidget {
#override
_AppDrawerState createState() => _AppDrawerState();
}
class _AppDrawerState extends State<AppDrawer> {
bool _value = false;
String message = "This is true";
void onChanged(bool value){
if(value){
setState(() {
message = "This is true";
print(message.toString());
String pos = "top";
_value = true;
});
}else{
setState(() {
message = "This is false";
print(message.toString());
String pos = "bottom";
_value = false;
});
}
}
#override
Widget build(BuildContext context) {
return Drawer(
child: new ListView(
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text("Suman Kumar"),
accountEmail: new Text ("Shoeman360#gmail.com"),
),
new ListTile(
title: new Text("Settings"),
trailing: new Icon(Icons.settings),
),
new SwitchListTile(
title: new Text("NavBar Position"),
activeColor: Colors.indigo,
value: _value,
onChanged: (bool value){
onChanged(value);
new Text (message);
}
),
new ListTile(
title: new Text("Close"),
trailing: new Icon(Icons.cancel),
onTap: () => Navigator.pop(context),
),
],
),
);
}
}
class NewPage {
final String title;
final Color color;
NewPage({this.title,this.color});
}
Fourth.dart (One of the class which calls the JSON api)
import 'package:flutter/material.dart';
import 'package:emas_app/Dependant.dart' as Dep;
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'model/crm_single_user_model.dart';
final String url = "http://crm.emastpa.com.my/MemberInfo.json";
//Future class for single user information
Future<SingleUser> fetchUser() async{
final response = await http.get(url);
final jsonresponse = json.decode(response.body);
return SingleUser.fromJson(jsonresponse[0]["Employee"]);
}
Future<String> jsonContent() async {
var res = await http.get(
Uri.encodeFull(
"http://crm.emastpa.com.my/MemberInfo.json"),
headers: {"Accept": "application/json"});
return res.body;
}
class Fourth extends StatefulWidget {
#override
FourthState createState() {
return new FourthState();
}
}
class FourthState extends State<Fourth> {
//String name;
#override
Widget build(BuildContext context) {
//New body widget
Widget newbody = new Container(
child: new Center(
child: new FutureBuilder(
future: fetchUser(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var userdata = snapshot.data;
//get the data from snapshot
final name = userdata.name;
final id = userdata.identification;
final company = userdata.company;
final dob = userdata.dob;
return new Card(
child: new Column(
children: <Widget>[
new ListTile(
title: new Text("Name"),
subtitle: new Text(name),
),
new ListTile(
title: new Text("Identification"),
subtitle: new Text(id),
),
new ListTile(
title: new Text("Company"),
subtitle: new Text(company),
),
new ListTile(
title: new Text("Date of Birth"),
subtitle: new Text(dob),
),
const Divider(
color: Colors.white,
height: 50.0,
),
new MaterialButton(
color: Colors.indigo,
height: 50.0,
minWidth: 50.0,
textColor: Colors.white,
child: new Text("More"),
onPressed: (){
Navigator.push(context,
new MaterialPageRoute(
builder: (context) => new Dep.Dependents(name: name,)
));
},
),
],
),
);
} else if(snapshot.hasError){
return new Text(snapshot.error);
}
return new Center(
child: new CircularProgressIndicator(),
);
},
),
),
);
return new Scaffold(
body: newbody,
);
}
}
crm_single_user_model.dart (Fourth.dart model class)
class SingleUser{
final String name, identification, company, dob;
SingleUser({this.name, this.identification, this.company, this.dob});
factory SingleUser.fromJson(Map<String, dynamic> ujson){
return SingleUser(
name: ujson["Name"].toString(),
identification: ujson["Identification"].toString(),
company: ujson["Company"].toString(),
dob: ujson["DateOfBirth"].toString()
);
}
}
Is there any way to call the api just once in Home.dart and not repeatedly send a new read request everytime i go into Fourth.dart?
Any assistance is very much appreciated.
You problem comes from your build method.Specifically the part where you do:
new FutureBuilder(
future: fetchUser(),
Basically, if your build where to be called again for any reason, you would call fetchUser again.
Why build would be called again? I never did a setState
setState is not the only way a widget can get rebuilt. Another situation where a widget can get rebuilt is when its parent updates (and created a new child instance).
In general, you should assume that build can be called at any time. Therefore you should do the least amount of work there.
To solve this problem, you should store your fetchUser future inside your state. Called from the initState. This will ensure that the fetchUser is called only once at the widget creation.
class FourthState extends State<Fourth> {
Future<SingleUser> userFuture;
#override
void initState() {
userFuture = fetchUser();
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: userFuture,
builder: ...
);
}
}