Flutter show Loading Indicator while building Complex Widget - flutter

I'm beginner at Flutter.
Currently in my app, I'm developing a "report screen" which includes complex widget like Timeseries chart.
What I'm noticed is that when I go to that "report screen", it takes about 3 seconds to appear this screen on the app. When I experiment by removing Timeseries chart widget from the screen, the app is responsive as best and instantly show the screen.
Therefore I would like to move this Timeseries Chart Widget building process to asynchronous and show the loading indicator while building the widget. By this way, I think the screen can appears instantly because no heavy widget building process at the start.
I've already tried the following way but no success.
// Chart Widget Building Method
Future<Widget> _buildChart(BuildContext context) async {
return Card(
elevation: 3.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 4.0),
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 8.0),
child: Row(
children: <Widget>[
_buildPeriodicButton(context, '1D'),
_buildPeriodicButton(context, '1W'),
_buildPeriodicButton(context, '1M'),
_buildPeriodicButton(context, '3M'),
],
),
),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 12.0),
child: ReportChart(data: _chartData),
),
],
),
),
);
}
// Screen build Method
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(context),
backgroundColor: CustomColors.GreyBackground,
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildFilters(context),
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none &&
snapshot.hasData == null) {
return Container(
child: Center(
child: Text("Loading"),
),
);
} else {
return snapshot.data;
}
},
future: _buildChart(context),
),
],
),
),
),
);
}
Thanks in advance for suggestions and solutions.

FutureBuilder(
builder: (context, snapshot) {
if (snapshot.hasData) {
return snapshot.data;
}
return Container(
child: Center(
child: Text("Loading"),
),
);
},
future: _buildChart(context),
),

I have used the fluttertoast: ^8.0.8 package as shown below. You can set the toast length to a longer duration if needed. FutureBuilder is not useful in the case, where your widget themselves take a long time render. FutureBuilder is useful while fetching the data required for your widgets.
#override
Widget build(BuildContext context) {
Fluttertoast.showToast(
msg: 'Loading...'
);
//Code for your complex widget here
}

Related

Removing button and load data

Hey guys I need help with removing this button and load data from json file without need to click on that button
Here's code
List _items = [];
// Fetch content from the json file
#override
Widget build(BuildContext context) {
Future readJson() async {
final String response =
await rootBundle.loadString('assets/aaaa.json');
final data = await json.decode(response);
setState(() {
_items = data['first'];
});
}
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(25),
child: Column(
children: [
ElevatedButton(
child: const Text('Load Data'),
onPressed: readJson,
),
// Display the data loaded from sample.json
_items.isNotEmpty
? Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
leading: Text(_items[index]["aaaaa"]),
title: Text(_items[index]["aaaaa"]),
subtitle: Text(_items[index]["aaaaaa"]),
),
);
},
),
)
: Container()
],
),
),
);
}
You should check out Future Builder. There are some good examples on that page of how to use the widget, including how to show different widgets depending on if the data was loaded, is in the process of loading, or there was an error. readJson would be the future in your case.
Call initState() before build function
#overrride
initState() {
readJson();
super.initState();
}
Calling the readJson() function just before returning Scaffold will do what you want.
Widget build(BuildContext context) {
//load the json content
readJson();
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(25),
child: Column(
children: [
// Display the data loaded from sample.json
_items.isNotEmpty
? Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
leading: Text(_items[index]["aaaaa"]),
title: Text(_items[index]["aaaaa"]),
subtitle: Text(_items[index]["aaaaaa"]),
),
);
},
),
)
: Container()
],
),
),
);}

How to modify UI to fill children widget after network call

Am fairly new to flutter please help how do i fill the children widget after performing network call?
class _BusResultScreenState extends State {
#override
Widget build(BuildContext context) {
helper myHelper = new helper();
myHelper.fetch(apiArg).then ((response) {
if(response['type']=="success") {
// Sample data from server in response.feedback
[
{"name":"bus1","id":"54"},
{"name":"bus2","id":"55"},
{"name":"bus3","id":"56"}
]
while(){
SharedBusCard(arg1,arg2,...) // This has to go into children Widget
}
}
});
return Scaffold(
backgroundColor: Colors.grey.shade200,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: <Widget>[
Material(
elevation: 4,
child: Container(
... code
.... code
SizedBox(height: 15),
Expanded(
child: Container(
width: double.infinity,
height: double.infinity,
child: ListView(
children: <Widget>[
//I wanted to display results here
SharedBusCard(arg1,arg2,...) // this is the card to be looped
],
),
),
)
],
),
),
),
);
}
}
Thanks for your help.
Use FutureBuilder widget for it. It is good for network calls and you can handle errors, show a loading screen in it. Here is documentation and a great video of using it.

Flutter TextField overflow bottom on keyboard up

This is the problem:
I have a grid (a crossword) and a list of questions below it. I need the list of questions to scroll indipendently from the grid. When I click on the grid to type the answer and the keyboard comes up I get an overflow error AND the grid doesn't move so the focused textfield that I use to input the answer is not visible (if it's low enough on the grid to be covered by the keyboard).
I tried all kind of combinations with ListView and Expanded widgets...no solution...I cannot use resizeToAvoidBottomInset: false because I need the grid to move up and keep the focused TextField visible.
Here is the code:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children:[
FutureBuilder(
future: grid,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Align(
alignment: Alignment.topCenter,
child: Container(
width: MediaQuery.of(context).size.width-8,
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
child: GridView.count(
padding: EdgeInsets.only(left:0.0,top:5.0,right:0.0,bottom: 0.0),
shrinkWrap: true,
crossAxisCount: 15,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
children: List.generate(snapshot.data.length, (index) {
if(gridFilled.length < snapshot.data.length) {
gridFilled.add(snapshot.data[index]);
}
return FocusScope(
node: _node,
child: Container(
decoration: BoxDecoration(
color: snapshot.data[index] == "#" ? Colors.black : Colors.white,
border: Border.all(color: Colors.black)),
child:
snapshot.data[index] == "#"
? Text('#')
: _isTextField(gridFilled[index], index),
));
}),
),
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
SizedBox(width: MediaQuery.of(context).size.width, height: 15.0,),
Expanded(
child: QPanel(dir: widget.dir, dbName: widget.xwordnumber),//this is a ListView with the questions
),
]),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children:<Widget>[
//just menu items
]
),
),
);
}
Unfortunately I'm not allowed to post pictures yet...not enough reputation..please, any help would be greatly appreciated!
wrap your Column inside SingleChildScrollView.
for example:
SingleChildScrollView(
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text('We move under cover and we move as one'),
Text('Through the night, we have one shot to live another day'),
Text('We cannot let a stray gunshot give us away'),
Text('We will fight up close, seize the moment and stay in it'),
Text('It’s either that or meet the business end of a bayonet'),
Text('The code word is ‘Rochambeau,’ dig me?'),
],
)
)
you can wrap your entire column inside SingleChildScrollView()

Correct way to display snapshot data in flutter with multiple widgets on the screen

Im really new at Flutter and Im having problems to display multiples Widgets and snapshot data.
What would be the correct way to display snapshot data inside a Column with multiples Widgets without stacic Height or special scroll ?
I mean I only want to have something like a SingleChildScrollView Where all the other widgets have to move with the _builderViewWidget but when I try to use the SingleChildScrollView I get a lot of errors like:
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
This is my code:
Widget build(BuildContext context) {
StoreDatum store = widget.store;
return Scaffold(
appBar: AppBar(
title: Text('HelloWorld')
),
body: Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(store.title, style: TextStyle(fontSize: 30.0),),
Text(store.details, style: TextStyle(fontSize: 20.0),),
_builderViewWidget(context), <---------------------------- BUILDERVIEWWIDGET
Container(
child: Text(store.address, style: TextStyle(fontSize: 20.0),),
)
]
),
),
);
}
Widget _builderViewWidget(BuildContext context){
return Container(
// height: 500.0, <------------------------------------- I DONT WANT THIS
child: Expanded(
child: Container(
child: _productBuilder(context)
)
)
);
}
Widget _productBuilder(BuildContext context) {
return FutureBuilder(
future: loadStoreProducts(),
builder: (context, snapshot) {
if(snapshot.hasData){
return _productWidget(context, snapshot.data);
}
else if(snapshot.hasError){
print(snapshot.error);
return Center(
child: Text('ERROR'),
);
}
return Center( child: CircularProgressIndicator() );
},
);
}
Widget _productWidget(BuildContext context, product){
return ListView.builder(
// physics: const NeverScrollableScrollPhysics(),
itemCount: product == null ? 0 : product.length,
itemBuilder: (context, i) {
return Container(
child: Row(
children: <Widget>[
Image.network(product[i].image),
Text(product[i].title, style: TextStyle(fontSize: 20.0),)
],
)
);
}
);
}
You have unbounded height in the vertical axis as your ListView will try to expand infinitely.
You can add shrinkWrap: true to your ListView.builder this will solve your problem.
Since you wanted the whole screen to scroll You will have to wrap Your Column in a SingleChildScrollView and remove all the Expanded widgets. And to the ListViewBuilder you can add a NeverScrollableScrollPyhsics this ensures the ListView doesn't scroll itself instead the whole screen in scrolled by SingleChildScrollView.

Flutter how do i show a video in alertDialog

I want to show a video in a alertDialog widget but i don't know how to show it in a alertDialog widget. here is my code.
class ResultScreen extends StatelessWidget {
static const routeResult = '/result-screen';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('The Result'),
backgroundColor: Colors.brown,
elevation: 0.0),
drawer: SideManu(),
body: ListView(children: <Widget>[
Container(
child: Stack(children: <Widget>[
Background(),
MoodText(),
ShowLevel(),
ActivityText(),
ActivityClip()
]))
]));
}
}
this is my code for button to open a video
class ActivityClip extends StatelessWidget {
final List<String> numbers = [
'Soft Music',
'Meditation',
'Pray',
'Breathing',
'Relex'
];
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(right: 10, left: 10, top: 350),
height: MediaQuery.of(context).size.height * 0.3,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: numbers.length,
itemBuilder: (context, index) {
return Container(
width: 200,
margin: const EdgeInsets.only(right: 10),
child: RaisedButton(
color: Colors.brown,
child: Container(
child: Center(
child: Text(
numbers[index].toString(),
style: TextStyle(color: Colors.white, fontSize: 30.0),
)),
),
onPressed: () {
activityVideo(context);
//alertDialog to show a video
},
));
}));
}
This is my code for a alertDialog. This dialog i plan to show a video clip.
void activityVideo(BuildContext context){
var alertDialog = AlertDialog(
title: Text("videoclip"),
actions: <Widget>[
FlatButton(
child: Text('Rate'),
onPressed: () {
rateVideo(context);
}),
FlatButton(
child: Text('Finish'),
onPressed: () {
Navigator.of(context).pop();
}),
],
);
showDialog(context: context,
builder: (BuildContext context){
return alertDialog;
}
);
}
Cloud you show me an example the way to show the video. Or if there are any good ways to show the video instead this way you can suggest me. Thank you so much.
here is a picture of my app to make you clearer. This is my page if you click to activity it will popup the video cilp.
home page
This is a dialog that i plan to show a video.
alertDialog
AlertDialog has a content field that you can easily send a widget to it.check document for a simple example. Furthermore, for showing the video you use video_player package. for a simple tutorial check this post published by flutter team.