Main.dart:
import 'package:flutter/material.dart';
import 'package:mypackage/widgets/home_widget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "My App",
theme: ThemeData(primarySwatch: Colors.blueGrey),
home: Home(),
);
}
}
Home.dart:
import 'package:flutter/material.dart';
import 'package:mypackage/widgets/secondary_page.dart';
import 'package:mypackage/widgets/home_view.dart';
import 'package:mypackage/widgets/settings_page.dart';
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
int currentPageIndex = 0;
final List<Widget> pageWidgets = [HomeView(), SecondaryPage(), SettingsPage()];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My App"),
centerTitle: true,
),
body: pageWidgets[currentPageIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: currentPageIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home), label: "Tab One"),
BottomNavigationBarItem(
icon: new Icon(Icons.account_balance), label: "Tab Two"),
BottomNavigationBarItem(
icon: new Icon(Icons.settings), label: "Tab Three"),
],
),
floatingActionButton: FloatingActionButton(onPressed: () {
// Update data from here
HomeView().updateDisplay();
}));
}
// Changes the index when the tapped page has loaded
void onTabTapped(int index) {
setState(() {
currentPageIndex = index;
});
}
}
HomeView.dart:
import 'package:flutter/material.dart';
import 'package:mypackage/models/mydisplay.dart';
import 'package:mypackage/network/mydata.dart';
class HomeView extends StatelessWidget {
final List<MyDisplay> dataList = [
new MyDisplay("Sample Display",
"SampleFile", 0),
];
Future<void> updateDisplay() async {
MyData myData = new MyData();
dataList.forEach((d) async {
d.changePercentage = await myData
.getDataPercentage("assets/data/" + d.fileName + ".xml");
print(d.dataName +
" change percentage: " +
d.changePercentage.toString() +
"%");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: new ListView.builder(
itemCount: dataList.length,
itemBuilder: (BuildContext context, int index) =>
buildCard(context, index)),
);
}
Widget buildCard(BuildContext context, int index) {
return Container(
child: Card(
color: Colors.teal.shade200,
child: Padding(
padding: const EdgeInsets.all(25),
child: Column(children: <Widget>[
Text(dataList[index].dataName,
style: new TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
Text(dataList[index].changePercentage.toString() + "%")
]))));
}
}
When I call the updateDisplay() method from the floatingActionButton it works as expected, the data gets printed to the console, however it doesn't seem to update the actual UI, the content of the cards, they simply remain at their initial set value.
To clarify: how do I update the content of the cards inside the listview (inside a stateless widget) from a stateful widget?
I am sorry if this is a duplicate question, I have looked and am continuing looking for answers to the question but I simply can't get it working.
You need to use a stateful widget since you cannot update stateless widgets. Check this link out for more information.The next problem, calling it, can be fixed by using globalKeys. The only weird thing about this is you have to keep both the Home stateful widget and HomeView stateful widget in the same dart file. . Try this code to make it work.
HOME VIEW
import 'package:flutter/material.dart';
import 'package:mypackage/widgets/secondary_page.dart';
import 'package:mypackage/widgets/settings_page.dart';
import 'package:mypackage/models/mydisplay.dart';
import 'package:mypackage/network/mydata.dart';
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
int currentPageIndex = 0;
final List<Widget> pageWidgets = [HomeView(), SecondaryPage(), SettingsPage()];
GlobalKey<_HomeViewState> _myKey = GlobalKey();// We declare a key here
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My App"),
centerTitle: true,
),
body: pageWidgets[currentPageIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: currentPageIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home), label: "Tab One"),
BottomNavigationBarItem(
icon: new Icon(Icons.account_balance), label: "Tab Two"),
BottomNavigationBarItem(
icon: new Icon(Icons.settings), label: "Tab Three"),
],
),
floatingActionButton: FloatingActionButton(onPressed: () {
// Update data from here
_myKey.currentState.updateDisplay();//This is how we call the function
}));
}
// Changes the index when the tapped page has loaded
void onTabTapped(int index) {
setState(() {
currentPageIndex = index;
});
}
}
class HomeView extends StatefulWidget {
Function updateDisplay;
HomeView({Key key}): super(key: key);//This key is what we use
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final List<MyDisplay> dataList = [
new MyDisplay("Sample Display",
"SampleFile", 0),
];
@override
void initState(){
super.initState();
widget.updateDisplay = () async {
MyData myData = new MyData();
dataList.forEach((d) async {
d.changePercentage = await myData
.getDataPercentage("assets/data/" + d.fileName + ".xml");
print(d.dataName +
" change percentage: " +
d.changePercentage.toString() +
"%");
});
setState((){});//This line rebuilds the scaffold
};
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: new ListView.builder(
itemCount: dataList.length,
itemBuilder: (BuildContext context, int index) =>
buildCard(context, index)),
);
}
Widget buildCard(BuildContext context, int index) {
return Container(
child: Card(
color: Colors.teal.shade200,
child: Padding(
padding: const EdgeInsets.all(25),
child: Column(children: <Widget>[
Text(dataList[index].dataName,
style: new TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
Text(dataList[index].changePercentage.toString() + "%")
]))));
}
}
We use setState((){}) to rebuild the widget. Just keep in mind one think. Wherever you use the updateDisplay method, dont make it so it runs in a loop after rebuilding. For eg. You use it in a future builder inside the child. THat way it will keep rebuilding
EDIT
We added a key to HomeView and now we can use that key like _myKey.currentState.yourFunction
. Hope I helped