How to modify UI to fill children widget after network call - flutter

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.

Related

How can I remove the visible border between two containers in a column?

does anyone know how to solve it so that there is no border between two elements in a column in the website? Thanks for any advice
Image
Code Here
class DesktopScreen extends StatelessWidget {
const DesktopScreen({super.key});
#override
Widget build(BuildContext context) {
return Sizer(
builder: (context, orientation, deviceType) {
return Scaffold(
body: Column(
children: [
Container(color: HexColor("#111340"), height: 5.h, child: Row(children: [],),),
Container(color: HexColor("#111340"), height: 95.h,)
],
)
);
}
);
}
}
I'm a newbie, so I apologize for any mistakes in the post
I don't think there's any error in the code you posted, the little space between the elements should not be there.
Here's your code running, there's no space between the containers:
https://zapp.run/edit/flutter-z8206198306?entry=lib/main.dart&file=lib/main.dart
I think the problem could be related to the extension you are using for providing height, or to the Sizer widget.
If you want to handle responsiveness, I suggest to look at this package: https://pub.dev/packages/layout
Use Flexible
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Flexible(
child: Container(
color: Colors.red,
),
),
Flexible(
flex: 4,
child: Container(
color: Colors.green,
),
),
],
),
);}

I am new to flutter and I think I have misunderstood the widget and layout system

If I want to add more buttons and text widgets where and how should I do it, should I make some sort of column and row system or am I totally off? And is my code programmed wrong?
import 'package:flutter/material.dart';
void main() {
runApp(
const HomeScreen(),
);
}
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Dice'),
centerTitle: true,
),
body: const Dice()));
}
}
class Dice extends StatefulWidget {
const Dice({Key? key}) : super(key: key);
#override
State<Dice> createState() => _DiceState();
}
class _DiceState extends State<Dice> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/1.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/2.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/3.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/4.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/5.png')))
],
),
));
}
}
I am going to add variables to the children in the container later.
For better understanding I would recommend you checking out this medium article. https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e Here you can view all the important layout widgets you can use.
In general you have a widget tree starting by MaterialApp and you can add as many items as you want. In flutter if you want multiple widgets you can use Row and Column for that. Both of them provides a children property in brackets [] there you can add multiple widgets inside separated by comma.
Most of the other widgets are also able to provide a children property where you can add even more children widgets. That's how the widget tree in general works. Actually you have unlimited possibility’s.
Your code is totally fine. By the way you can also create custom widgets if the plenty widgets of flutter doesn't fit your use case.
In your example you can add whatever you want in your row, text, more images, buttons, everything you like.
Here you can check out the official widget catalog of flutter: https://docs.flutter.dev/development/ui/widgets
You can place a Column/ListView in between your Center and Row widgets, then you could add multiple rows to it like below:
class _DiceState extends State<Dice> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/1.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/2.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/3.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/4.png'))),
Expanded(
child: Container(
margin: const EdgeInsets.all(15),
child: Image.asset('images/5.png')))
],
),
Row(children: [/* more content here */]),
],
),
),
);
}
}

Add scrollable and refreshable data table between fixedWidth widgets

Totally I need a scrollable DataTable with refresh possibility on pull down between header and footer fixed width widgets.
I have a widget, using on every page in my app. THis widget return a Scaffold with appbar and body like column (). This widget used like CommonPage(title, widgetsArrayForBodyColumn) from other widgets.
For now I need to use a follow widgets in that body:
Lookup (for filtering or for example, any fixed height widget)
DataTable (for show data)
Card (to show another data)
DataTable should be scrollable and refreshable on pull down.
I tried many different ways, but still has no success. My last solution is using stack, but list hidden beside the card.
I can't understand how to achieve my goal: have refreshing datatable between non scrollable widgets in a column.
class CommonPage extends StatefulWidget {
final String title;
final List<Widget> children;
const CommonPage({
Key? key,
required this.title,
required this.children,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
...
body: Column(children: [
FixedHeightWidget(),
PageScreen(),
]);
}
}
class PageScreen {
#override
Widget build(BuildContext context) {
return CommonPage(
title: Title,
children: [
FixedHeightWidget(),
PageList(),
],
);
}
}
class PageList {
Widget build(BuildContext context) {
//TODO Return fixedWidthWidget at top, expandedRefreshableScrollableDataTable, fixedWidthWidget at bottom
}
}
My current solution: (almost achieves my goal, but as mentioned card hides part of list and no ways to scroll and check bottom of the list):
return Expanded(
child: Stack(
children: [
RefreshIndicator(
onRefresh: onRefresh,
child: ListView(
children: [
listItems.isNotEmpty
? DataTable(...)
: Container(),
],
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
alignment: Alignment.bottomCenter,
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 5),
child: Card(...),
),
),
),
],
),
],
),
);
I found the solution:
return Expanded(
child: Column(
children: [
Expanded(
child: RefreshIndicator(
onRefresh: onRefresh,
child: ListView(
children: [listItems.isNotEmpty
? DataTable(...)
: Container(),
],
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5),
child: Card(...),
),
],
),
);

AnimatedContainer - How do I expand only one and the rest stay below?

So there's something I'm working on and I want to have a list of these "capsules" (rounded rectangle containers). When the user taps on any given one of them, it expands to the full screen, while the rest stay on a lower layer and don't do anything.
I'm using AnimatedContainer and GestureDetector to change their state. When there's only one, it works perfectly for what I want to do. Meanwhile, as soon as I add more in a Column, because it's a single Widget I coded inside a GestureDetector with a single boolean, they all open at the same time. And I understand that even if I code them separately, it will basically just push the surrounding ones out of the way, not open above them. How would I deal with this?
I tried searching this and couldn't find anything helpful. Hopefully the answer to this will help future projects too.
bool chatCapsuleTapped = false;
bool hasFullSize = false;
#override
Widget build(BuildContext context) {
Widget _chatCapsuleAnimation() {
return GestureDetector(
onTap: () {
setState(() {
chatCapsuleTapped = !chatCapsuleTapped;
hasFullSize = true;
});
},
child: AnimatedContainer(
width: !chatCapsuleTapped ? 350 : MediaQuery.of(context).size.width,
height: !chatCapsuleTapped ? 75 : MediaQuery.of(context).size.height,
//color: !chatCapsuleTapped ? Colors.grey.withOpacity(1) : Colors.grey,
decoration: BoxDecoration(
color: !chatCapsuleTapped ? Colors.grey.shade500 : Colors.grey.shade300,
borderRadius: !chatCapsuleTapped ? BorderRadius.circular(40) : BorderRadius.circular(0),
),
child: !chatCapsuleTapped ? Container(child: Container(),) : Container(),
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
),
);
}
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_chatCapsuleAnimation(),
],
),
),
);
}
} ```
You can use Hero:
Place each widget inside a Hero widget, assign it a tag based on the index.
Then have a Full-Screen page, which contains the bigger version of the widget, but with the same tag as of the tapped item.
Sample Grabbed from here, you can paste it in DartPad
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Basic Hero Animation'),
),
body: SingleChildScrollView(
child: Column(
children: List<Widget>.generate(5, (index) {
return InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Full-Screen Page'),
),
body: Container(
child: Hero(
// TAG should be same as the tapped item's index
tag: index.toString(),
child: SizedBox(
child: Container(
color: Colors.grey[(index + 1) * 100]),
),
),
),
);
},
),
);
},
child: Hero(
// Assigning tag of item as its index in the list
tag: index.toString(),
child: Container(
height: 200, color: Colors.grey[(index + 1) * 100]),
));
}))),
);
}
}
I've put the destination page within the scope of the main file for simplicity, but you can make a seperate Widget and accept index as parameter for the Bigger Hero's tag

Flutter show Loading Indicator while building Complex Widget

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
}