In my demo app I need to load a 2 JSON file from server. Both JSON has large data in it. I my Flutter app I call the json using Future + async + await than I call to create a widget with runApp. In the body I try to activate a CircularProgressIndicator. It shows appBar and its content as well as empty white page body and 4 or 5 seconds later loads the data in actual body.
My question is I need to show the CircularProgressIndicator first and once the data load I will call runApp(). How do I do that?
// MAIN
void main() async {
_isLoading = true;
// Get Currency Json
currencyData = await getCurrencyData();
// Get Weather Json
weatherData = await getWeatherData();
runApp(new MyApp());
}
// Body
body: _isLoading ?
new Center(child:
new CircularProgressIndicator(
backgroundColor: Colors.greenAccent.shade700,
)
) :
new Container(
//… actual UI
)
You need to put the data/or loading indicator inside a scaffold, show the scaffold everytime whether you have data or not, the content inside you can then do what you want to do.`
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hello Rectangle',
home: Scaffold(
appBar: AppBar(
title: Text('Hello Rectangle'),
),
body: HelloRectangle(),
),
),
);
}
class HelloRectangle extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.greenAccent,
height: 400.0,
width: 300.0,
child: Center(
child: FutureBuilder(
future: buildText(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator(backgroundColor: Colors.blue);
} else {
return Text(
'Hello!',
style: TextStyle(fontSize: 40.0),
textAlign: TextAlign.center,
);
}
},
),
),
),
);
}
Future buildText() {
return new Future.delayed(
const Duration(seconds: 5), () => print('waiting'));
}
}
`
Related
In my Flutter application, I am trying to pass JSON data from one route to another. The challenge I am facing is how to pass a list as a parameter. The first screen contains a list of JSON data that has been fetched, and I aim to show the complete details of each item when the user clicks on the respective ListTile.
you will find the onTap() in JsonParsingPodo.dart
here's my code :
posts.dart (plain old dart object file)
class PostList {
final List<Post> posts;
PostList({required this.posts});
factory PostList.fromJson(Map<String, dynamic> parsedJson) {
List<dynamic> postsJson = parsedJson['posts'] as List;
List<Post> posts = <Post>[];
posts = postsJson.map((e) => Post.fromJson(e)).toList();
return PostList(posts: posts);
}
}
class Post {
int userId;
int id;
String title;
String body;
Post(
{required this.id,
required this.body,
required this.title,
required this.userId});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
body: json['body'],
title: json['title'],
userId: json['userId']);
}
}
JsonParsingPodo.dart (First Screen)
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:podo_practice/posts.dart';
import 'display.dart';
class JsonParsingPodo extends StatefulWidget {
const JsonParsingPodo({super.key});
#override
State<JsonParsingPodo> createState() => _JsonParsingPodoState();
}
class _JsonParsingPodoState extends State<JsonParsingPodo> {
late Future<PostList> data;
#override
void initState() {
super.initState();
Network network = Network("https://dummyjson.com/posts");
data = network.loadPost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("PODO: json"),
),
body: Center(
// ignore: avoid_unnecessary_containers
child: Container(
child: FutureBuilder(
future: data,
builder: (context, AsyncSnapshot<PostList> snapshot) {
List<Post> allposts;
if (snapshot.hasData) {
allposts = snapshot.data!.posts;
return createListView(allposts, context);
}
return const CircularProgressIndicator();
}),
),
));
}
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData()),
// *what to pass here??*
);
},
),
],
);
});
}
}
class Network {
final String url;
Network(this.url);
Future<PostList> loadPost() async {
final response = await get(Uri.parse(Uri.encodeFull(url)));
if (response.statusCode == 200) {
//ok
return PostList.fromJson(json.decode(response.body));
} else {
throw Exception("Failed to load data. ");
}
}
}
DisplayData.dart (Second Screen)
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
const DisplayData({super.key});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}
I have recently started learning Flutter and don't have much knowledge. I tried reading articles on Stack Overflow about this thing, but I didn't understand much. So, I have decided to post a question for help. Please assist me in completing the following code.
On the "Display Data" page, I need to display the **title **and its **description **when the user clicks on the ListItem.
onListile tap send particular object using index
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
Post post = data[index]
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData(post:post)),
// *what to pass here??*
);
},
),
],
);
});
}
}
get post on constructor to display
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
final Post post;
const DisplayData({super.key,required this.post});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}
This is my complete code and i don't know what kind of error i have made
Correct it if you know, as i am beginner in flutter.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Mydata(),
);
}
}
class Mydata extends StatefulWidget {
const Mydata({super.key});
#override
State<Mydata> createState() => _MydataState();
}
class _MydataState extends State<Mydata> {
Future<List<String>> ebdetails() async {
var response =
await http.get(Uri.parse('http://117.247.181.113:8000/eb/1/'));
return jsonDecode(response.body);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
elevation: 0,
centerTitle: true,
title: const Text(
'Json Datas',
style: TextStyle(
color: Colors.black,
),
),
backgroundColor: Colors.white,
),
body: Center(
child: FutureBuilder(
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('Data Error'),
);
} else if (snapshot.hasData) {
return Center(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return Text(
snapshot.data![i],
);
},
));
} else {
return const CircularProgressIndicator();
}
},
future: ebdetails(),
),
),
);
}
}
I am fetching data over local ip but it seems to have some sort of error i have made, but its hard for me to find..
It shows only "Data error which i have given in Futurebuilder..
[
{
"id": 1,
"R_Current": -1.0,
"Y_Current": -1.0,
"B_Current": -1.0,
"R_Voltage": 208,
"Y_Voltage": 235,
"B_Voltage": 208,
"UPS_Voltage": 100,
"UPS_Current": 143.0,
"UPS_Battery": 99
}
]
so according to your data it is not the list of the String change the return type of the method to this
Future<List<dynamic>> ebdetails() async {
var response =
await http.get(Uri.parse('http://117.247.181.113:8000/eb/1/'));
return jsonDecode(response.body);
}
Edit:
Ok so your problem was that you pass map to the Text() widget and the text widget needs string as a parameter so you have to convert the snapshot.data to string and then pass it to the Text widget.
snapshot.data.toString()
try to convert the response into a custom Dart object
see this
[1]: https://docs.flutter.dev/cookbook/networking/fetch-data
I have changed the code and got the answer i.e snapshot.data![i].toString()
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return Text(
snapshot.data![i].toString(),
);
Hey I have the problem that I want to transfer the data from a ListTile which was pressed. So i can read the data from a Json file on another page.
I have already written in the code where I want to get something where. I hope you know what I mean if not just ask under here. I always look in and answer. I've been through all sorts of sites but none of them helped me. So here now. You are my last hope
So hier is my Code
class PokemonDB extends StatefulWidget {
_PokemonDB createState() => _PokemonDB();
}
class _PokemonDB extends State<PokemonDB> {
List pokemon = const [];
Future loadPokemon() async {
var content = await rootBundle.loadString("json/pokemon.json");
var collection = json.decode(content);
setState(() {
pokemon = collection;
});
}
void initState() {
loadPokemon();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
backgroundColor: Colors.black,
),
body: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider(),
itemCount: pokemon.length,
itemBuilder: (BuildContext context, int index) {
var pokemonn = pokemon[index];
return Container(
child: ListTile(
onTap: () async{
Map name = await Navigator.push(
context,
MaterialPageRoute<Map>(builder: (BuildContext context) {
return ShinyHuntCounter(); <-- from here I want the data on which click was
},
),);
},
isThreeLine: false,
title: Text(
pokemonn['name'],
style: TextStyle(
fontFamily: 'pokemon',
fontSize: 30,
color: Colors.black
),
),
leading: Image(image: AssetImage(pokemonn['image'])),
),
decoration:
BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(50)),
color: Color.fromRGBO(234, 180, 59, 1),
),
);
},
),
);
}
}
I think it would be simple like this,
In your ShinyHuntCounter class,
class ShinyHuntCounter extends StatefulWidget {
final String pokemonn;
const ShinyHuntCounter(this.pokemonn);
#override
ShinyHuntCounterState createState() => ShinyHuntCounterState();
}
class ShinyHuntCounterState extends State<ShinyHuntCounter> {
#override
Widget build(BuildContext context) {
return Text(widget.pokemonn); // Here you direct access using widget
}
}
and for passing the data, do something like this,
MaterialPageRoute<Map>(builder: (BuildContext context) {
return ShinyHuntCounter(pokemonn['name']); }, )
Hope that suits your case.
Maybe this is a simple question, but I can't find the answer to it.
My app has 2 screens. 1st has a single button
onPressed: () {
fetchCurrentTitle();
Navigator.push(context,
MaterialPageRoute(builder: (context) => Screen2Widget()));
},
fetchCurrentTitle() method fetches data from json and decodes it.
I can see the return using:
final streamFullTitle = json.decode(response.body)['data'][0]['title'];
print(streamFullTitle);
I get the desired response of the current title in the console.
In the 2nd screen I have a hardcoded List. Where items have these values:
class List {
String id;
String streamer;
String logoUrl;
String title;
}
The first three attribute in List class dont need to change so they are hardcoded. I just need to assign the title value fromfetchCurrentTitle() to the String title. in class List.
Look of one of my list items
My fetchCurrentTitle() works as intended
Future<String> fetchCurrentTitle() async {
http.Response response = await http.get(...
I want the user to push the button on the first screen to go to the second screen and show a spinner with title "looking for title" and then get the new title instead of waiting fetchCurrentTitle() to complete only entering the second screen.
Thank you in advance.
You can try to run your fetchCurrentTitle() in the second screen on
void initState() {
super.initState();
fetchCurrentTitle()
/// show or set visibility for loading spinner
}
After you get the title value, you can simply assign new title by
List existingList = new List(id,streamer,logoUrl,title);
existingList.id = titleValueFromApi
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sample_project_for_api/Employee.dart';
void main() => runApp(MaterialApp(
title: "App",
home: MyApp(),
));
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('home page'),
),
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondScreen()));
},
child: const Text('First Page')),
)),
);
}
}
class SecondScreen extends StatefulWidget {
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
bool _isLoading = false;
Employee sampleData;
#override
void initState() {
super.initState();
getYouData();
}
Future<String> loadPersonFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
getYouData() async {
setState(() {
_isLoading = true;
});
String jsonString = await loadPersonFromAssets();
final data = employeeFromJson(jsonString);
sampleData = data;
// this is where you get the data from the network
Future.delayed(const Duration(seconds: 5), () {
// this is sample delay for you to know the delay.
// you can say this is loading your data
setState(() {
_isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Container(
child: _isLoading
//here give your message getting the title
? CircularProgressIndicator()
: Card(
child: Column(
children: <Widget>[
Text('your 1st hardcoded text'),
Text('your 2st hardcoded text'),
Text('your 3st hardcoded text'),
Text(
'This is your dynamic data after fetching :${sampleData.employeeName}')
],
),
),
),
),
),
);
}
}
check out this example you will give you an idea of what to do
1) going from one page to another page
2) loading you data , while that showing the spinner
3) on fetching the data update the UI.
let me know about this.
Thanks.
Try this,
import 'dart:convert';
import "package:flutter/material.dart";
import 'package:http/http.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Page1(),
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
body: Center(
child: RaisedButton(
child: Text("Goto Page2"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page2(),
),
);
},
),
),
);
}
}
class Page2 extends StatefulWidget {
#override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
Future<void> _initLoader;
String _title;
#override
void initState() {
_initLoader = _loadInitData();
super.initState();
}
Future<void> _loadInitData() async {
await Future.delayed(Duration(seconds: 2));
//_title = await fetchCurrentTitle();
_title = "This is the Loaded Title";
}
Future<String> fetchCurrentTitle() async {
Response response = await get("...");
return json.decode(response.body)['data'][0]['title'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: FutureBuilder(
future: _initLoader,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CircularProgressIndicator(),
const SizedBox(height: 8.0),
Text("Looking for Title"),
],
),
);
else if (snapshot.hasError)
return Center(
child: Text("Error: ${snapshot.error}"),
);
else
return Center(
child: Text("$_title"),
);
},
),
);
}
}
I'm learning flutter and want to fetch various images which are the thumbnail of the cartoon. I used HTTP library and fetched response data.
But, how can I extract that image?
Website: https://comic.naver.com/webtoon/weekdayList.nhn?week=
Future<http.Response> _getData() async {
return await http.get('https://comic.naver.com/webtoon/weekdayList.nhn?week=');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
),
body: Center(
child: RaisedButton(
child: Text("Fetching"),
onPressed: (){
_getData().then((response){
//dom.Document document = parser.parse(response.body);
print(response.body);
}).catchError((e) => print(e));
},
),
),
);
}
What I want to do is below.
Fetching web page as HTML code
Find image url of each cartoon
Fetch that image
Here you have a basic example, after you press the top-right button, you will get the images in a ListView:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as parser;
import 'package:html/dom.dart' as dom;
...create your StatefulWidget
class ParsingWidgetState extends State<ParsingWidget> {
List<String> list = List();
void _getData() async {
final response =
await http.get('https://comic.naver.com/webtoon/weekdayList.nhn?week=');
dom.Document document = parser.parse(response.body);
final elements = document.getElementsByClassName('thumb');
setState(() {
list = elements
.map((element) =>
element.getElementsByTagName("img")[0].attributes['src'])
.toList();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
actions: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
_getData();
},
),
],
),
body: ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return Image.network(
list[index],
height: 200.0,
);
},
));
}
}
Try using FutureBuilder instead setState, this is just a working sample.
More info:
https://docs.flutter.io/flutter/widgets/FutureBuilder-class.html
https://flutter-academy.com/async-in-flutter-futurebuilder/