I am very new to Flutter and have been trying for a few days now to get this right. Either I get stuck with the set state that does not reload(With a spinner) or the JSON cant is decoded as my example.
I want to get the JSON into a listview and then when the floatingActionButton button is pushed refresh the widget with the CircularProgressIndicator. This is what I have so far.
All examples that I find seem not to be Null safe and again I am lost.
My example says "List' is not a subtype of type 'Map<String, dynamic>" and I can see this is because my JSON is a list List ??.
A few pointers would be greatly appreciated.
This is the JSON its pulling:
[
{
"userId": 1,
"id": 1,
"title": "How to make friends"
},
{
"userId": 2,
"id": 1,
"title": "Gone with the wind"
}
]
```
Future<Album> fetchAlbum() async {
print("Fetching json....");
final response = await http.get(
Uri.parse(myLocksEp),
);
if (response.statusCode == 200) {
print(response.body);
return Album.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load album');
}
}
class Album {
final int id;
final String title;
Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
id: json['id'],
title: json['name'],
);
}
}
void main() {
runApp(mylocks());
}
class mylocks extends StatefulWidget {
#override
_MyAppState createState() {
return _MyAppState();
}
}
class _MyAppState extends State<mylocks> {
late Future<Album> _futureAlbum;
#override
void initState() {
super.initState();
_futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(8.0),
child: FutureBuilder<Album>(
future: _futureAlbum,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
//Error message goers here
}
}
return const CircularProgressIndicator();
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh_outlined, color: Colors.black),
backgroundColor: Colors.grey[200],
onPressed: () {
setState(() {
_futureAlbum = fetchAlbum();
});
},
),
),
);
}
}
Sorry for the long post, I hope I make sense
Thank you in advance
Robby
If I'm not wrong, here you are providing a List<Map<String, dynamic>>
return Album.fromJson(jsonDecode(response.body));
while the Album.fromJson is expecting to receive a Map<String, dynamic>
So, thats why you are getting the error "List' is not a subtype of type 'Map<String, dynamic>"
Apart from that, take into account that every time you build the widget, FutureBuilder will always make a call to the future that you pass to it, so in this case, when you press the FloatingActionButton, you will make a call, and then, when the widget start to rebuild, you will make another one.
You should make some adjustments to avoid this. You could change the FloatingActionButton onPressed callback to be empty:
setState(() {});
Again, if I'm not wrong this will make the widget rebuild itself since you are saying that the state has changed, and when rebuilding, the FutureBuilder will make the request, and therefore, update the list.
EDIT BASED ON THE COMMENTS
class _MyAppState extends State<mylocks> {
late Future<Album> _futureAlbum;
//ADD ALBUMS VAR
List<Album> _albums = [];
#override
void initState() {
super.initState();
//INVOKE METHOD AND SET THE STATE OF _albums WHEN IT FINISHES
fetchAlbum().then((List<Album> albums){
setState((){_albums = albums);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(8.0),
child: Column(
//REPLACE FUTURE BUILDER WITH DESIRED WIDGET, WHILE _albums IS EMPTY IT WILL RENDER A CircularProgressIndicator
children: [
_albums.isEmpty ? Center(
child: CircularProgressIndicator(),
) : ..._albums,
]
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh_outlined, color: Colors.black),
backgroundColor: Colors.grey[200],
onPressed: () {
//AGAIN, WHEN FINISHING IT SHOULD REBUILD THE WIDGET AND THE DATA
fetchAlbum().then((List<Album> albums){
setState((){_albums = albums);
});
},
),
),
);
}
}
Don't worry about creating models for your Json just use this link to autogenerate a model.
Related
I don't know what I'm doing wrong, the truth is, I'm barely learning.
I just want to consume an api and display the information on the screen https://api.coinlore.net/api/tickers/
this is the request class
class Peticion extends StatefulWidget {
const Peticion({Key? key}) : super(key: key);
#override
_PeticionState createState() => _PeticionState();
}
class _PeticionState extends State<Peticion> {
Future<List<Crypto>> fetchData() async {
final response =
await http.get(Uri.parse('https://api.coinlore.net/api/tickers/'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// este es un array de Strings
final list = data['data'] as List;
return list
.map((e) => Crypto(
id: e['id'],
name: e['name'],
symbol: e['symbol'],
))
.toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
#override
Widget build(BuildContext context) {
return Center(
child: FutureBuilder<List<Crypto>>(
future: fetchData(),
builder: (BuildContext context, AsyncSnapshot<List<Crypto>> snapshot) {
if (snapshot.hasData) {
final lista = snapshot.data!;
return ListView.builder(
itemCount: lista.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(lista[index].name),
subtitle: Text(lista[index].symbol),
leading: Text(lista[index].id.toString()),
);
},
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
);
}
}
here the class model
class Crypto {
final String id;
final String symbol;
final String name;}
Crypto({
required this.id,
required this.symbol,
required this.name,})
factory Crypto.fromJson(Map<String, dynamic> json) {
return Crypto(
id: json['id'],
symbol: json['symbol'],
name: json['name'],}
and the following happens
I will also leave the main screen in case it helps
return Scaffold(
appBar: AppBar(
title: const Text('Coinlore'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Peticion(),
],
),
);
I would also leave the errors in the console but they are infinite and they are not specific or it is not known which one to show.
From what I see, it looks like an overflow issue. Basically the Column you're using as a parent for your Peticion widget, wants to grow as long as possible vertically. So there's no constraints or limit on it. And when the Peticion widget you're using gets data, it becomes a ListView which also wants to grow as big vertically. Now inside a infinitely growing area ListView just lost all it's constraints.
But yeah, just to put it simply. Try doing this
Scaffold(
appBar: AppBar(
title: const Text('Coinlore'),
),
body: Peticion(),
);
This will solve the issue I just mentioned. And that's what I think so far, from your code.
The API im using is a car registry where you type in a numberplate and it will show details about the vehicle. Basically i have tried implementing a Textfield where i can retrieve it's value so i can insert in the API url (VALUE FROM TEXTFIELD). I have have tried implementing it using this tutorial: https://docs.flutter.dev/cookbook/forms/retrieve-input but with no luck.
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://v1.motorapi.dk/vehicles/(VALUE FROM TEXTFIELD)'),
headers: {"X-AUTH-TOKEN": "rfrzsucnc7eo3m5hcmq6ljdzda1lz793",
"Content-Type": "application/json",
"Accept": "application/json",
});
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
I have tried to inserting Textfield in the widget but that didn't work
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
TextEditingController nummerpladeController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child:
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column( mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [ Text("Registreringsnummer: ""${snapshot.data!.registration_number}"),
Text("Status: ""${snapshot.data!.status}"),
Text("Type: ""${snapshot.data!.type}"),
Text("Brug: ""${snapshot.data!.use}"),
Text("Første registrerings dato: ""${snapshot.data!.first_registration}"),
Text("Vin nummer: ""${snapshot.data!.vin}"),
Text("Mærke: ""${snapshot.data!.make}"),
Text("Model: ""${snapshot.data!.model}"),
Text("Variant: ""${snapshot.data!.variant}"),
Text("Model type: ""${snapshot.data!.model_type}"),
Text("Farve: ""${snapshot.data!.color}"),
Text("Bil type: ""${snapshot.data!.chasis_type}"),
Text("Brændstof: ""${snapshot.data!.fuel_type}"),
Text("Sidste syn: ""${snapshot.data!.date}"),
], );
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
You have to assign the TextEditingController to a TextField widget like so:
TextField(
controller: nummerpladeController,
);
To retrieve its value you have to call nummerpladeController.text
Furthermore, you currently are not able to access your nummerpladeController in your build method because it is defined in the initState method. To fix this, do the following:
late final TextEditingController nummerpladeController;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
nummerpladeController = new TextEditingController();
}
You can read more about what late is here: https://dart.dev/null-safety/understanding-null-safety#lazy-initialization
I build a simple search widget for flutter web. Everything working fine but after I got the search results, I have to click twice on the result to select a specific search result. Please help me to figure out the problem. I tried for several day but no luck. I'm using flutter 2.5.2 version.
darpad link to run the code
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(MaterialApp(
home: SearchView(),
));
}
class SearchView extends StatefulWidget {
#override
State<SearchView> createState() => _SearchViewState();
}
class _SearchViewState extends State<SearchView> {
String searchResult = '';
final textController = TextEditingController();
final List<String> data = ['Result 1', 'Result 2', 'Result 3', 'Result 4'];
Future<List<String>> loadData() {
return Future.delayed(Duration(seconds: 1), () {
if (this.textController.text.trim().length != 0) {
return data;
} else {
return [];
}
});
}
#override
void initState() {
this.textController.addListener(this._onTextChanged);
super.initState();
}
void _onTextChanged() {
print('text cahnged');
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Brand'),
),
body: SingleChildScrollView(
child: Column(
children: [
TextFormField(
controller: this.textController,
),
FutureBuilder(
future: loadData(),
builder:
(BuildContext context, AsyncSnapshot<List<String>> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.hasData) {
print("future build");
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
for (String result in snapshot.data)
InkWell(
onTap: () {
print('Clicked');
setState(() {
this.textController.clear();
this.searchResult = result;
});
},
child: Text(result),
),
],
);
} else {
return CircularProgressIndicator();
}
},
),
Text('Search result is ${searchResult}'),
],
),
),
);
}
}
Please help me to fix this issue. Thank you and have a nice day
This weird behavior happens because of a flutter issue. Before flutter version 2.5, Text change listeners only listen for text changes. But from version 2.5, listeners also listen for focus change events. Need to use onChanged method in TextFormField until flutter fix the issue.
so I have a GET request that needs authorization headers, and I've tried using Postman manually where it works just fine, but not in my Dart code.
So I have this announcements.dart Provider class:
class Announcements with ChangeNotifier {
List _items = [];
String? token;
// late Future<Announcement> futureAnnouncement;
Announcements(this.token, this._items);
List get items {
return [..._items];
}
Future<void> fetchAnnouncements() async {
String url = "https://api-staging.xxx.us.org/1.0/announcements";
try {
final response = await http.get(
Uri.parse(url),
headers: {HttpHeaders.authorizationHeader: token!},
);
final extractedData = json.decode(response.body);
final List loadedProducts = [];
extractedData.forEach((prodId, data) {
loadedProducts.add(
Announcement(id: prodId, title: data['title'], body: data['body']));
});
print(response);
_items = loadedProducts;
print(_items);
notifyListeners();
} catch (e) {
throw (e);
}
and this is my main.dart function where the ChangeNotifier works:
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
ChangeNotifierProxyProvider<Auth, Announcements>(
create: (_) => Announcements(null, []),
update: (_, auth, previousProducts) => Announcements(
auth.token,
previousProducts == null ? [] : previousProducts.items,
),
),
],
child: Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(
title: 'Xxx',
theme: ThemeData(),
home: NavigationScreen(),
),
),
);
}
}
This is how the announcement is called:
class AnnouncementScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
final announcementData = Provider.of<Announcements>(context);
return Scaffold(
backgroundColor: Color(0xff1e1e1e),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(
height: 90,
),
Text(
'Good Morning, John',
style: TextStyle(
fontSize: 32,
fontFamily: 'Casper',
color: Color.fromRGBO(247, 245, 232, 1),
),
),
SizedBox(
height: 10,
),
Expanded(
child: SizedBox(
height: 200.0,
child: FutureBuilder(
future: Provider.of<Announcements>(context)
.fetchAnnouncements(),
builder: (ctx, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: announcementData.items.length,
itemBuilder: (context, index) {
return Column(
children: [
_tile(announcementData.items[index].title,
announcementData.items[index].body),
Divider(
thickness: 4,
indent: 0,
endIndent:
MediaQuery.of(context).size.width / 1.4,
color: Color.fromRGBO(198, 158, 96, 1),
),
],
);
}),
),
),
),
],
),
),
),
);
}
}
Thanks for helping, really appreciate it!
There are certain things you need to change, I don't know exactly what's the problem in this code.
I think the fetching is happening but the widget rebuilds so many times, which makes the future be fetched every time the rebuild happens, which again trigger the rebuild
Change the Widget to StatefulWidget
Extract the fields inside didChangeDependencies (since you need context)
class AnnouncementScreen extends StatefulWidget {
#override
_AnnouncementScreenState createState() => _AnnouncementScreenState();
}
class _AnnouncementScreenState extends State<AnnouncementScreen > {
late final announcementFuture;
late final Announcements announcement;
bool isInitialised = false;
#override
void didChangeDependencies() {
super.didChangeDependencies();
if(!isInitialised ){
announcement = Provider.of<Announcements>(context);
announcementFuture = announcement.fetchAnnouncements();
isInitialised = true;
}
}
#override
Widget build(BuildContext context) {
return ....(
FutureBuilder(
future:announcementFuture ,
builder: (ctx,snapshot){
//code
}
),
...
);
}
}
Have you checked if the auth token is loaded in your project?
It may be easier to debug this if you create a simple Dart command line app that makes the calls you need. Then you can do something like:
void main() async {
try {
final auth = Auth();
final token = auth.whateverMethodGetsToken();
// Note: Announcements class shouldn't really need ChangeNotifier
final announcements = Announcements(token, []);
final result = announcements.fetchAnnouncements();
print(result);
} catch (e) {
print(e);
}
}
This will tell you if the problem is in your networking code and make it easier to debug it.
I'm new to the flutter world and mobile app development and struggling with how I should pass data throughout my app. This is my code, How can I pass snapshot data from futurebuilder to another futurebuilder on the same page? help, please
**Widget _buildProgrammCard()**
From this widget Card I need to pass the location id which is in the futurebuilder to another futurebuilder.
Widget _buildProgrammCard() {
return Container(
height: 90,
child:
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 4,
margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
child:
FutureBuilder(
future: databaseHelper2.Lastlocation(),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("there is problem");
}
return snapshot.hasData
? Text("Location :" +snapshot.data.id)
: Center(child: CircularProgressIndicator(
),
);
}
),
),
);
}
Widget build(BuildContext context)
And this is the second Widget that I need to pass the location id into it from another widget.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
body: FutureBuilder(
future: databaseHelper2.Getweither(location_id),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("there is problem !");
}
return snapshot.hasData
? ItemList(list: snapshot.data)
: Center(child: CircularProgressIndicator(
),
);
}
),
);
}
Flutter rebuilds widgets often so FutureBuilder shouldn't call a future function directly. (A widget may call its build function up to 60 times a second.)
Instead a FutureBuilder should only receive a future value from an async function called elsewhere.
In a StatefulWidget, the most common place to initiate long-running operations is in its initState() method.
The location data, retrieved during the first Widget initState, can be passed to the second widget, just like a regular constructor argument.
You'll access it in the 2nd widget's State class with widget.locationId.
import 'package:flutter/material.dart';
class FirstFuturePage extends StatefulWidget {
#override
State<StatefulWidget> createState() => FirstFutureState();
}
class FirstFutureState extends State<FirstFuturePage> {
Future<int> locationId = Future.value(-1);
#override
void initState() {
// TODO: implement initState
super.initState();
someAsyncCall();
}
Future<void> someAsyncCall() async {
// just returns the number 0 after 2 seconds & assigns it to "locationId" var
locationId = Future.delayed(Duration(seconds: 2), () => 0);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: FutureBuilder<int>(
future: locationId,
builder: (context, snapshot) {
int _locationId = snapshot.data;
if (snapshot.hasData)
return SecondWidget(_locationId);
return Text('Looking up location...');
},
),
),
),
);
}
}
class SecondWidget extends StatefulWidget {
final int locationId;
SecondWidget(this.locationId);
#override
_SecondWidgetState createState() => _SecondWidgetState();
}
class _SecondWidgetState extends State<SecondWidget> {
Future<String> weatherData = Future.value('Unknown');
#override
void initState() {
super.initState();
loadWeather(widget.locationId); // Use the locationId passed into widget
}
/// Takes locationId from First widget and looks up weather data for location
Future<void> loadWeather(int locationId) async {
List<String> weatherDataStore = List<String>.from(['Rainy', 'Sunny']);
weatherData = Future.delayed(
Duration(seconds: 2), () => weatherDataStore[locationId]
);
}
#override
Widget build(BuildContext context) {
int _locId = widget.locationId;
return FutureBuilder<String>(
future: weatherData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('Weather for location $_locId is: ${snapshot.data}');
}
return Text('Loading Weather...');
},
);
}
}
State Management Solutions
When you get tired of passing values around like in the above example, you can use a State Management package or create your own that suits your needs.
Here's a nice overview from Jeff Delaney about various options:
https://fireship.io/lessons/flutter-state-management-guide/
And also check out Get which isn't mentioned in the above:
https://pub.dev/packages/get
Some of the above State management solutions (e.g. Provider) help you use Flutter-native state functionality correctly (because its rather complicated), while others completely avoid that and provide a framework separate from the Widget lifecycle (e.g. Get).
Thanks Baker for your response but not exactly what i meant
these are my two futures and my class
This is my future that returns the Location from her i need to pass the location id to the another future
Future<Location> Lastlocation() async {
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/location/getlastlocation?token=" + value;
http.Response response = await http.get(
myUrl,
headers: {
'Accept': 'application/json',
//'Authorization': 'token $value'
},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
return Location.fromJson(json.decode(response.body));
} else {
// then throw an exception.
throw Exception('Failed to load album');
}
}
This is my future that returns List of weather that depends on location id
Future<List> Getweither(String ID) async {
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/sensors/getDeviceByid/$ID?token=" + value;
http.Response response = await http.get(myUrl,
headers: {
'Accept': 'application/json',
});
print("myUrldevice :"+myUrl);
print("status :"+response.statusCode.toString());
return json.decode(response.body);
}
This is my class Location
// To parse this JSON data, do
//
// final location = locationFromJson(jsonString);
import 'dart:convert';
List<Location> locationFromJson(String str) => List<Location>.from(json.decode(str).map((x) => Location.fromJson(x)));
String locationToJson(List<Location> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Location {
Location({
this.automaticIrrigation,
this.coordinates,
this.createdDate,
this.sensorIds,
this.id,
this.siteName,
this.description,
this.v,
});
bool automaticIrrigation;
List<double> coordinates;
DateTime createdDate;
List<String> sensorIds;
String id;
String siteName;
String description;
int v;
factory Location.fromJson(Map<String, dynamic> json) => Location(
automaticIrrigation: json["AutomaticIrrigation"],
coordinates: List<double>.from(json["Coordinates"].map((x) => x.toDouble())),
createdDate: DateTime.parse(json["Created_date"]),
sensorIds: List<String>.from(json["Sensor_ids"].map((x) => x)),
id: json["_id"],
siteName: json["SiteName"],
description: json["Description"],
v: json["__v"],
);
Map<String, dynamic> toJson() => {
"AutomaticIrrigation": automaticIrrigation,
"Coordinates": List<dynamic>.from(coordinates.map((x) => x)),
"Created_date": createdDate.toIso8601String(),
"Sensor_ids": List<dynamic>.from(sensorIds.map((x) => x)),
"_id": id,
"SiteName": siteName,
"Description": description,
"__v": v,
};
}
and this is my homePage
import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sidebar_animation/Services/DataHelpers.dart';
import 'package:sidebar_animation/sidebar/sidebar_layout.dart';
import '../bloc.navigation_bloc/navigation_bloc.dart';
import 'package:sidebar_animation/constants.dart';
import 'package:flutter/gestures.dart';
import 'package:sidebar_animation/bloc.navigation_bloc/navigation_bloc.dart';
class HomePage extends StatelessWidget with NavigationStates {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DatabaseHelper2 databaseHelper2 = new DatabaseHelper2();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
body: ListView(
FutureBuilder(
future: databaseHelper2.Getweither(location_id),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("there is problem !");
}
return snapshot.hasData
? ItemList(list: snapshot.data)
: Center(child: CircularProgressIndicator(
),
);
}
),
);
}
Widget _buildProgrammCard() {
return Container(
height: 90,
child:
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 4,
margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
child:
FutureBuilder(
// future: databaseHelper.getData(),
future: databaseHelper2.Lastlocation(),
builder: (context,snapshot) {
if (snapshot.hasError)
{
print(snapshot.error);
print("mochkla lenaa *");
}
return snapshot.hasData
? Text("Location :" +snapshot.data.siteName)
: Center(child: CircularProgressIndicator(
),
);
}
),
),
);
}
class ItemList extends StatelessWidget{
List list;
ItemList({this.list});
ScrollController _controller = new ScrollController();
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
scrollDirection: Axis.horizontal,
itemExtent: 190.0,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 14),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
item.storyUrl,
),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black26,
BlendMode.darken,
),
),
borderRadius: BorderRadius.circular(10.0),
color: Colors.grey,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"temp :",
style: TextStyle(color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 24),
child:
Text(
list[i]['Weither']['Temp'],
),
),
],
),
),
);
},
),
}
}
Finaly i need to get the location id from the first future that return Location to the second future Getweither(String ID) .