I am trying to run charts from a library in flutter. I can't run in using main.dart.
Main.dart:
import './widgets/chart.dart';
void main() {
runApp(
new MaterialApp(
home: PointsLineChart(),
),
);
}
chart.dart:
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
class PointsLineChart extends StatelessWidget {
final List<charts.Series> seriesList;
final bool animate;
PointsLineChart(this.seriesList, {this.animate});
/// Creates a [LineChart] with sample data and no transition.
factory PointsLineChart.withSampleData() {
return new PointsLineChart(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
#override
Widget build(BuildContext context) {
return new charts.LineChart(seriesList,
animate: animate,
defaultRenderer: new charts.LineRendererConfig(includePoints: true));
}
/// Create one series with sample hard coded data.
static List<charts.Series<LinearSales, int>> _createSampleData() {
final data = [
new LinearSales(0, 5),
new LinearSales(1, 25),
new LinearSales(2, 100),
new LinearSales(3, 75),
];
return [
new charts.Series<LinearSales, int>(
id: 'Sales',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: data,
)
];
}
}
/// Sample linear data type.
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
The error that i am getting is that in main.dart i need to input something in order to run chart.dart. In PointsLineChart(),
it gives me error:
1 required argument(s) expected, but 0 found.dart(not_enough_required_arguments)
(new) PointsLineChart(List> seriesList, {bool animate}) → PointsLineChart
The constructor of PointsLineChart takes two argument:
PointsLineChart(this.seriesList, {this.animate});
whereas in your main.dart, you give no arguments:
home: PointsLineChart(),// here you need to add two arguments!!!
Change the code as below:
runApp(
new MaterialApp(
home: PointsLineChart(PointsLineChart.createSampleData(), animate: false),
),
);
also change _createSampleData to createSampleData to make it public.
Related
I'm making an app, which has a theme manager, light mode, dark mode, and system mode.
I think that the way I manage the state with redux, prevent me to reload the app with the hot reload, I explain:
If I have a scaffold with a background, from the themedata, if the thememode is currently dark, and the background color is Color(0xFF1F1F1F) (a shade of black), and I change it to Color(0xFFFFFFFF) (Pure white), then I use hot reload, it doesn't work, and I need to restart the whole app with hot restart to see changes.
The same with my theme manager, I use radiobuttons to manage it, if I change the theme to light or dark, it works fine.
if I change the mode to system, it works fine, but with the system theme mode in which the app were opened, if I change the system theme mode of my phone, it doesn't work. in this case StoreProvider.dispatch doesn't work, store.dispatch neither, I have to use the hot restart.
Here the code that can cause the problem.
main.dart:
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:async_redux/async_redux.dart';
import 'package:hive/hive.dart';
import 'package:app_name/Redux/States/AppState.dart';
import 'package:app_name/UI/Screens/AppHome.dart';
import 'package:app_name/Utilities/Themes.dart';
import 'package:app_name/Utilities/functions.dart';
import 'package:app_name/Utilities/extensions.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
Box box = await initHive();
SettingsState settingsState = SettingsState(
themeMode: box.get("theme").toString().themeModeFromString,
);
Store<AppState> store = Store(
initialState: AppState(settings: settingsState),
);
runApp(App(store: store));
}
class App extends StatelessWidget {
final Store<AppState> store;
App({
required this.store,
});
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: StoreConnector<AppState, SettingsState>(
converter: (Store<AppState> store) => store.state.settings,
builder: (BuildContext context, SettingsState settings) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Carleo',
theme: lightTheme,
darkTheme: darkTheme,
themeMode: settings.themeMode,
home: Focus(
onFocusChange: (hasFocus) =>
SystemChrome.setEnabledSystemUIOverlays([]),
autofocus: true,
descendantsAreFocusable: true,
child: AppHome(),
),
);
},
),
);
}
}
Here the file AppHome.dart:
import 'package:app_name/UI/Widgets/Radio%20buttons.dart';
import 'package:flutter/material.dart';
import 'package:carleo/UI/Screens/SelectAccess.dart';
import 'package:carleo/UI/Screens/Home.dart';
import 'package:carleo/UI/Widgets/CircularIndicator.dart';
import 'package:carleo/Utilities/Database Utilities.dart';
import 'package:app_name/Utilities/Themes.dart';
class AppHome extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeGetter.primary(context),
body: ThemeRadioButton(),
);
}
}
Here Radio Buttons.dart:
import 'package:flutter/material.dart';
import 'package:async_redux/async_redux.dart';
import 'package:app_name/Redux/States/AppState.dart';
import 'package:app_name/Redux/Actions/Actions.dart';
class ThemeRadioButton extends StatelessWidget {
Widget build(BuildContext context) {
return StoreConnector<AppState, SettingsState>(
converter: (Store<AppState> store) => store.state.settings,
builder: (BuildContext context, SettingsState settings) {
return Wrap(
children: [
ListTile(
leading: Radio<ThemeMode>(
value: ThemeMode.light,
fillColor: MaterialStateProperty.all(Colors.black),
groupValue: settings.themeMode,
onChanged: (ThemeMode? mode) {
StoreProvider.dispatch<AppState>(
context,
ThemeChanger(
payload: mode ?? ThemeMode.light,
),
);
},
),
title: Text("Light"),
),
ListTile(
leading: Radio<ThemeMode>(
value: ThemeMode.dark,
fillColor: MaterialStateProperty.all(Colors.black),
groupValue: settings.themeMode,
onChanged: (ThemeMode? mode) {
StoreProvider.dispatch<AppState>(
context,
ThemeChanger(
payload: mode ?? ThemeMode.dark,
),
);
},
),
title: Text("Dark"),
),
ListTile(
leading: Radio<ThemeMode>(
value: ThemeMode.system,
fillColor: MaterialStateProperty.all(Colors.black),
groupValue: settings.themeMode,
onChanged: (ThemeMode? mode) {
StoreProvider.dispatch<AppState>(
context,
ThemeChanger(
payload: mode ?? ThemeMode.system,
),
);
},
),
title: Text("System"),
),
],
);
},
);
}
}
Here any other thing that can help:
ThemeData darkTheme = ThemeData(
backgroundColor: Color(0xFF1F1F1F),
accentColor: Color(0xFF101217),
primaryColor: Color(0xFFFFFFFF),
buttonColor: Color(0xFF0D47A1),
brightness: Brightness.dark,
);
ThemeData lightTheme = ThemeData(
backgroundColor: Color(0xFFFFFFFF),
accentColor: Color(0xFFFFFFFF),
brightness: Brightness.light,
);
class ThemeGetter {
static Color primary(BuildContext context) {
return Theme.of(context).backgroundColor;
}
static Color accent(BuildContext context) {
return Theme.of(context).accentColor;
}
static Color contrast(BuildContext context) {
return Theme.of(context).primaryColor;
}
static Color secondary(BuildContext context) {
return Theme.of(context).buttonColor;
}
}
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' show ThemeMode;
extension StringEnumExtension on String {
ThemeMode get themeModeFromString => ThemeMode.values.firstWhere(
(e) => describeEnum(e) == this,
orElse: () => ThemeMode.system,
);
}
extension ThemeModeExtensions on ThemeMode {
String get name => describeEnum(this);
}
import 'package:flutter/material.dart' show ThemeMode;
class AppState {
final SettingsState settings;
AppState({SettingsState? settings})
: this.settings = settings ?? SettingsState();
AppState.copy({
required AppState state,
}) : this.settings = state.settings;
AppState copyWith({int? counter, SettingsState? settings}) => AppState(
settings: settings ?? this.settings,
);
#override
operator ==(Object another) =>
identical(this, another) ||
(another is AppState && this.settings == another.settings);
#override
int get hashCode => super.hashCode;
}
class SettingsState {
final ThemeMode themeMode;
SettingsState({
ThemeMode? themeMode,
}) : this.themeMode = themeMode ?? ThemeMode.system;
SettingsState.copy({
required SettingsState state,
}) : this.themeMode = state.themeMode;
SettingsState copyWith({ThemeMode? themeMode, ThemeMode? radioValue}) =>
SettingsState(
themeMode: themeMode ?? this.themeMode,
);
#override
operator ==(Object another) =>
identical(this, another) &&
(another is SettingsState && another.themeMode == this.themeMode);
#override
int get hashCode => super.hashCode;
}
import 'package:async_redux/async_redux.dart';
import 'package:flutter/material.dart' show ThemeMode;
import 'package:hive/hive.dart';
import 'package:carleo/Redux/States/AppState.dart';
import 'package:carleo/Utilities/extensions.dart';
class ThemeChanger extends ReduxAction<AppState> {
final ThemeMode payload;
ThemeChanger({
required this.payload,
});
#override
Future<AppState> reduce() async {
Box box = await Hive.openBox("Settings");
box.put("theme", payload.name);
return state.copyWith(
settings: state.settings.copyWith(
themeMode: payload,
),
);
}
}
Any help will be accepted. and thanks in advance.
EDIT:
I've noticed that, even if settings.themeMode is ThemeMode.system, and, in the store connector (the one which builds the MaterialApp), the themeData values are correct, if I use later the same color with Theme.of(context) (like I do in the background of the scaffold in AppHome), the color printed is not the correct one, is the color of the last hot restart.
I put this in the StoreConnector builder to notice that:
Brightness brightness =
SchedulerBinding.instance!.window.platformBrightness;
bool darkModeOn = brightness == Brightness.dark;
print(settings.themeMode);
switch (settings.themeMode) {
case ThemeMode.light:
print(lightTheme.primaryColor);
break;
case ThemeMode.dark:
print(darkTheme.primaryColor);
break;
case ThemeMode.system:
if (darkModeOn)
print(darkTheme.primaryColor);
else
print(lightTheme.primaryColor);
}
and simply this code to notice that the colors are different in different widgets:
print(Theme.of(context).backgroundColor);
Some code changes to the app’s main() or initState() methods might not be visible in the refreshed UI on hot-reload.
As a general rule, if the modified code is downstream of the root
widget’s build() method, then hot reload behaves as expected. However,
if the modified code won’t be re-executed as a result of rebuilding
the widget tree, then you won’t see its effects after hot reload.
This may be the reason for the change to theme data not reflected after hot-reload since it is defined in the app's main().
So from Flutter documentation
Hot reload loads code changes into the VM and re-builds the widget
tree, preserving the app state; it doesn’t rerun main() or
initState().
According to the flutter docs - hot reload is not enabled for flutter web as of 16/07/21
Flutter hot reload doc
Kia Kaha,
Mike Smith
I am trying to integrate some native code in my project. For that, I am using the new Pigeon package: https://pub.dev/packages/pigeon
On Android it works just fine but on iOS, whenever I try to call the method written in swift (on button press), it throws a PlatformException(channel-error, Unable to establish connection on channel., null, null)
I've setup the flutter starting project and then I am calling the native methods when the floatingActionButton is pressed. When the native method is executed, it returns a String saying "Hello from Android" on the android side and "Hello from Xcode" on iOS.
main.dart file:
import 'package:flutter/material.dart';
import 'package:platforms/pigeon.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#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, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
Api api = Api();
final searchReply = await api.search(SearchRequest());
print(searchReply.result);
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
MainActivity.java file:
package com.example.platforms;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
private class Api implements Pigeon.Api {
#Override
public Pigeon.SearchReply search(Pigeon.SearchRequest arg) {
Pigeon.SearchReply searchReply = new Pigeon.SearchReply();
searchReply.setResult("Hello from Android!");
return searchReply;
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Pigeon.Api.setup(getFlutterEngine().getDartExecutor().getBinaryMessenger(), new Api());
}
}
AppDelegate.swift file:
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate, Api {
var engine: FlutterEngine = {
let result = FlutterEngine.init()
// This could be `run` earlier in the app to avoid the overhead of doing it the first time the
// engine is needed.
result.run()
return result
}()
func search(_ input: SearchRequest, error: AutoreleasingUnsafeMutablePointer<FlutterError?>) -> SearchReply? {
let reply = SearchReply()
reply.result = "Hello from Xcode!!!!"
return reply
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
ApiSetup(engine.binaryMessenger, self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Result of onPressed on Android:
Result of onPressed on iOS:
What's also worth noting is that when I call the code in onPressed in the didChangedDependencies function, the code in swift does run, and the result does show up, but the same exception is then thrown again. Which means that the channel does get created, I am just using it wrong.
When this is added to main.dart
#override
void didChangeDependencies() async {
Api api = Api();
final searchReply = await api.search(SearchRequest());
print(searchReply.result);
super.didChangeDependencies();
}
It prints the result from swift and then throws the same error.
I think the BinaryMessenger is getting set incorrectly.
I tried this and it worked:
In the didFinishLaunchingWithOptions method get the rootViewController and cast it as FlutterBinaryMessenger:
let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
// get binaryMessenger
let binaryMessenger = rootViewController as! FlutterBinaryMessenger
// set binaryMessenger
ApiSetup(binaryMessenger, self)
The complete method becomes like this:
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self);
let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
// get binaryMessenger
let binaryMessenger = rootViewController as! FlutterBinaryMessenger
// set binaryMessenger
ApiSetup(binaryMessenger, self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
I'm trying to display a comment stream from Reddit API. I"m using Streambuilder to stream contents as it arrives and displays it as list view thing is I can only view present stream content and this will disappear as new stream contents appear replacing the old ones. If I don't mention item count inside listview.builder prints contents infinitely still new stream appears.
is there a way to display contents along with previous contents in a scrollable fashion and automatically scroll down as a new stream message appears??
Assuming that the comment stream returns individual (and preferably unique) comments one at a time rather than as a list, what you need to do is store the incoming comments in a state object such as a list. When a new comment comes through the stream, you add it to the list and then trigger a widget rebuild.
What you are doing right now is replacing state with each new stream element rather than accumulating them. Using the code you provided, I have edited it to behave as an accumulator instead. Notice the List<Comment> comments = <Comment>[] object added to state. I have also removed the StreamBuilder since that isn't helpful for this use case.
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:draw/draw.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: RedditFlutter(),
debugShowCheckedModeBanner: false,
);
}
}
class RedditFlutter extends StatefulWidget {
RedditFlutter({Key key}) : super(key: key);
#override
_RedditFlutterState createState() => _RedditFlutterState();
}
class _RedditFlutterState extends State<RedditFlutter> {
var comments;
ScrollController _scrollController =
new ScrollController(initialScrollOffset: 50.0);
List<Comment> comments = <Comment>[];
StreamSubscription<Comment>? sub;
var msg = '';
Future<void> redditmain() async {
// Create the `Reddit` instance and authenticated
Reddit reddit = await Reddit.createScriptInstance(
clientId: 'clientid',
clientSecret: 'clientsecret',
userAgent: 'useragent',
username: 'username',
password: 'password', // Fake
);
// Listen to comment stream and accumulate new comments into comments list
sub = reddit.subreddit('cricket').stream.comments().listen((comment) {
if (comment != null) {
// Rebuild from state when a new comment is accumulated
setState(() {
comments.add(comment);
})
}
});
}
#override
void initState() {
// TODO: implement initState
redditmain();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Reddit"),
centerTitle: true,
),
body: Center(
child: Container(
child: ListView.builder(
controller: _scrollController,
itemCount: comments.length,
itemBuilder: (context, index) {
final Comment comment = comments[index];
return Card(
child: ListTile(
leading: Image.asset('assets/criclogo.png'),
title: Text(comment.body),
trailing: Icon(Icons.more_vert),
),
);
},
),
);
),
);
}
#override
void dispose() {
sub?.cancel();
super.dispose();
}
}
Note that I have not tested this code so there may be (trivial) bugs. Still, conceptually, it should be fine.
I want to pass data from page1 to page2 using PageRouteBuilder(for animation matters), problem is how to pass it. I don't to sacrifice my animation by using MaterialPageRoute().
/// My button in page 1
Listview.builder(
...
...
...
onTap: () {
Navigator.of(context).push(_createRouteSelectType(12)); //data i want to pass
},
),
/// My PageRouteBuilder
Route _createRouteSelectType(buCode) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => page2(buCode),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
var begin = Offset(0.0, 1.0);
var end = Offset.zero;
var curve = Curves.decelerate;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}
/// My page 2 class / receiver
import 'package:flutter/material.dart';
class page2extends StatefulWidget {
final int buCode;
page2({Key key, #required this.buCode }) : super(key: key);
#override
_LoadT createState() => _LoadT();
}
Give this package a shot: auto_route, it:
Let you specify your route animation ( and there are already some ready animations)
Takes care of creating a class for the parameters your page takes, so it solves your problem in the question
So I want to set the children of my GridView dynamically so I can set it when I want. Currently this is the whole class.
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/CustomColors.dart';
import 'package:flutter_app/quote/Quote.dart';
import 'package:flutter_app/quote/QuoteView.dart';
import 'package:flutter_app/section/Section.dart';
import 'package:flutter_app/quote/QuoteData.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
static List<QuoteData> data = [];
_readJson() async {
data.clear();
var url = 'https://www.dropbox.com/s/7k280ca5dktlhoo/quotes.json?dl=1';
var httpClient = new HttpClient();
httpClient.getUrl(Uri.parse(url)).then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) {
response.transform(utf8.decoder).listen((contents) {
List<Map> decoded = JSON.decode(contents);
decoded.forEach((m) {
String url = m["url"];
String title = m["title"];
String sectionString = m["section"];
Section section;
for (Section element in Section.values) {
if (element.toString() == "Section." + sectionString) {
section = element;
}
}
List<Quote> quotes = m["quotes"];
data.add(new QuoteData(url, title, section, quotes));
});
});
});
}
#override
Widget build(BuildContext context) {
_readJson();
return new MaterialApp(
title: 'Quotes',
theme: new ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or press Run > Flutter Hot Reload in IntelliJ). Notice that the
// counter didn't reset back to zero; the application is not restarted.
primarySwatch: CustomColors.black,
),
home: new MyHomePage(title: 'Quotes'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static Section currentSection = Section.movies;
void _onTileClicked(QuoteData quote) {
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new QuoteView(quote)));
}
List<Widget> _getTiles(Section section) {
final List<Widget> tiles = <Widget>[];
for (var i in MyApp.data) {
if (i.section != section) {
continue;
}
tiles.add(new GridTile(
child: new InkResponse(
enableFeedback: true,
child: new Image.network(
i.url,
fit: BoxFit.cover,
),
onTap: () => _onTileClicked(i),
)));
}
return tiles;
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
final double itemHeight = (size.height - kToolbarHeight - 24) / 2;
final double itemWidth = size.width / 2;
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return new Scaffold(
appBar: new AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: new Text(currentSection
.toString()
.replaceAll("Section.", "")
.substring(0, 1)
.toUpperCase() +
currentSection.toString().replaceAll("Section.", "").substring(1)),
),
body: new Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: new GridView.count(
crossAxisCount: 2,
childAspectRatio: (itemWidth / itemHeight),
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: _getTiles(currentSection)),
),
);
}
}
So right now on startup, it launches the application but MyApp.data is empty because the json has to be read so the GridView will be empty, when I refresh the application, the GridView won't be empty because MyApp.data won't be empty anymore. I want to be able to set the children after the json gets read, also I need to be able to change it dynamically because I will add a function for switching sections.
The same goes for the title, I also need to be able to change it dynamically when switching sections.
You can create a loading widget and wait for the request to finish when the request is finished hide the loading and show the grid than rebuild the state. but you need to have a statefullWidget not statelessWidget.
You can see how i use it on the code below I added my comments to the code
class _ChildrenPageState extends State<ChildrenPage> {
//declare the _load to true so it will show the loading when the page is loaded
bool _load = true;
ChildrenService _childrenService = new ChildrenService();
List children = [];
//I call the _rebuild function to rebuild the widgets and show the data
void _rebuild() {
setState(() {
});
}
#override
Widget build(BuildContext context) {
//I call the request to get my data when it is finished i put _load to false so the loading will hide and call the _rebuild function to rebuild the widgets and i have put if so when the widget is built it will not rebuild it a second time.
_childrenService.getChildren(children).then((data){
if(data && _load){
_load = false;
_rebuild();
}
});
//the below widget show the loading container if _load is true else it will show the dataTable in your app you should add the grid and you can pass the data that you got from the request
Widget loadingIndicator = _load ? new Container(
color: Colors.grey[300],
width: 70.0,
height: 70.0,
child: new Padding(
padding: const EdgeInsets.all(5.0),
child: new Center(
child: new CircularProgressIndicator()
)
),
) : new JLDataTable(
data: children,
);
return new Scaffold(
drawer: new Drawer(
child: MenuList.menuList,
),
appBar: new AppBar(title: const Text('Data tables')),
body: new ListView(
padding: const EdgeInsets.all(20.0),
children: <Widget>[
new Align(
child: loadingIndicator,
alignment: FractionalOffset.center
)
]
)
);
}
}