Persisting data in a flutter application - android

I am building an app and in it, I have the names of people in a list from which I could add/delete, etc.. The problem is this list is not saved when I close the app, which is inconvenient.
I heard you can use shared Preferences to save simple objects like this, without complicating things like using SQLite and json.
So I'd like to know what's the suggested way to persist this data and load it etc.
Thanks in Advance and have a great day :)
Here is the code:
import 'package:flutter/material.dart';
import 'package:zakif_yomi3/NewPerson.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<String> people = [];
void _addNewPerson(String name) {
setState(() {
people.add(name);
});
}
void _startAddNewPerson(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (_) {
return GestureDetector(
onTap: () {},
child: NewPerson(_addNewPerson),
behavior: HitTestBehavior.opaque,
);
},
);
}
void _deletePerson(int value ) {
setState(() {
people.removeAt(value);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'People',
style: TextStyle(fontSize: 30),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewPerson(context),
)
],
),
body: ListView.builder(
itemCount: this.people.length,
itemBuilder: (context, value) {
return Card(
color: Colors.amberAccent[200],
elevation: 3,
child: Container(
child: ListTile(
leading: Text(value.toString()),
title: Text(
people[value],
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
_deletePerson(value);
},
),
),
),
);
},
),
);
}
}
And the NewPerson object:
import 'package:flutter/material.dart';
class NewPerson extends StatefulWidget {
final Function addTx;
NewPerson(this.addTx);
#override
_NewPersonState createState() => _NewPersonState();
}
class _NewPersonState extends State<NewPerson> {
final _nameController = TextEditingController();
void _submitData() {
final name = _nameController.text;
widget.addTx(
name
);
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextField(
decoration: InputDecoration(labelText: 'Name'),
controller: _nameController,
onSubmitted: (_) => _submitData(),
),
RaisedButton(
child: Text('Add Person'),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).textTheme.button.color,
onPressed: _submitData,
),
],
),
),
);
}
}

You could use this functions to persist and load data from shared preferences.
Get SharedPreferences from here.
To persist data to SharedPreferences, called after adding or deleting a new element to the list.
_persistData() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
await preferences.setStringList("persons", _people);
}
To load data from SharedPreferences, usually called in initState.
_loadData() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
_people = preferences.getStringList("persons");
});
}

Related

Integrating Hive with Flutter for local data copy

I am trying the code put by Resocoder for integrating the Hive with Flutter. Everything was going fine but i got stuck at a place from where i cant figure out what to do. If you see contactsbox is throwing error stating that itsa n object and i cant use lingth property on it or even any other property. I have market the partof the code in bold throwing error. Any idea why is this error happening. HOw shall i use contactsBox as List unable to understand it. Any help would be great
contact_page.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'new_contact_form.dart';
import 'contact.dart';
class ContactPage extends StatelessWidget {
const ContactPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hive Tutorial'),
),
body: Column(
children: [
Expanded(
child: _buildListView(),
),
NewContactForm(),
],
),
);
}
Widget _buildListView() {
return ValueListenableBuilder(
valueListenable: Hive.box('contacts').listenable(), builder:
(context, contactsBox, _) {
return ListView.builder(**itemCount: contactsBox.length** , itemBuilder: (context, index) {
final contact = contactsBox.getAt(index) as Contact;
return ListTile(
title: Text(contact.name!),
subtitle: Text(contact.age.toString()),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
contactsBox!.putAt(
index,
Contact('${contact.name}*', contact.age + 1),
);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
contactsBox.deleteAt(index);
},
)
],
),
);
}
);
}
);
}
new_contact_form.dart
import 'package:db_app/contact.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
class NewContactForm extends StatefulWidget {
const NewContactForm({Key? key}) : super(key: key);
#override
State<NewContactForm> createState() => _NewContactFormState();
}
class _NewContactFormState extends State<NewContactForm> {
final _formKey = GlobalKey<FormState>();
String? _name;
String? _age;
void addContact(Contact cnt) {
final contactBox = Hive.box('contacts');
contactBox.add(cnt);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
onSaved: (value) => _name = value,
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(labelText: 'Age'),
onSaved: (value) => _age = value,
keyboardType: TextInputType.number,
),
ElevatedButton(
onPressed: () {
_formKey.currentState!.save();
final newContact = Contact(_name, int.parse(_age!));
addContact(newContact);
},
child: Text('Add New Contact'),
),
],
),
));
}
}

why isn't the listview showing the text that input by the user

I need your help.
I'm making a function for my app that has the user add something by pressing the add button, it will then navigate to an adding page and then from the adding page it will add a new listtile in the listview. But I don't know why the text that was input by the user cannot be shown. Can anyone help me?
import 'package:flutter/material.dart';
import 'storage for each listview.dart';
import 'package:provider/provider.dart';
import 'adding page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => Storage(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage()
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
final provider = Provider.of<Storage>(context, listen: false);
final storageaccess = provider.storage;
return Scaffold(
appBar: AppBar(
title: Text('app'),
),
body: ListView.builder(
itemCount: storageaccess.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(storageaccess[index].title),
subtitle: Text(storageaccess[index].titlediary.toString()),
onTap: () {},
onLongPress: () {
//delete function here
},
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => addpage()));
}, //void add
tooltip: 'add diary',
child: Icon(Icons.add),
) // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
/// this one I did not do anything first this one for later today just make UI
class Things {
String title;
DateTime titlediary;
Things({required this.title, required this.titlediary});
}
class addpage extends StatefulWidget {
#override
_addpageState createState() => _addpageState();
}
class _addpageState extends State<addpage> {
String title = '';
#override
Widget build(BuildContext context) {
final TextEditingController titleController=TextEditingController(text: title);
final formKey = GlobalKey<FormState>();
return Scaffold(
appBar: AppBar(
title: Text('enter page ',style: TextStyle(fontSize: 30),),
),
body:Form(
key: formKey,
child: Column(
children: [
TextFormField(
controller: titleController,
autofocus: true,
validator: (title) {
if (title!.length < 0) {
return 'enter a title ';
} else {
return null;
}
},
decoration: InputDecoration(
border: UnderlineInputBorder(),
labelText: 'title',
),
),
SizedBox(height: 8),
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black),
),
onPressed: () {
if (formKey.currentState!.validate()) {
final accessthing = Things(
title: title,
titlediary: DateTime.now(),
);
final provideraccess = Provider.of<Storage>(context, listen: false);
provideraccess.add(accessthing);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>MyHomePage()));
}
},
child: Text('Save'),
),
],
),),);
}
}
class Storage extends ChangeNotifier {
List<Things> storage = [
Things(
title: 'hard code one ',
titlediary: DateTime.now(),
),
Things(
title: 'hard code two ',
titlediary: DateTime.now(),
),
Things(
title: 'hard code two ',
titlediary: DateTime.now(),
),
Things(
title: 'hard code two ',
titlediary: DateTime.now(),
),
];
void add(Things variablethings) {
storage.add(variablethings);
} notifyListeners();
}
after the user clicks the addbutton, it will send them to an adding page, then after clicking save, the data will be saved into a storage page and then the provider will add the data provided by the user, but the text will not show on the listtile.
I suspect this is happening because you are Navigating to HomePage again using,
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>MyHomePage()));
but this time it is not connected to your provider context.
[
In detail: As you have used ChangeNotifierProvider() in MyApp then connected the MyHomePage() there. But if you push again in Navigator, then fluter creates a separate instance of MyHomePage() widget. Which will not be connected to ChangeNotifierProvider() in MyApp
].
In place of this, use Navigator.of(context).pop();
And in onPressed() use this,
floatingActionButton: FloatingActionButton(
---> onPressed: () async {
---> await Navigator.push(
context, MaterialPageRoute(builder: (context) => addpage()));
---> setState((){});
},

The instance member 'setState' can't be accessed in an initializer

im Very new in flutter . i dont know what to do to fix this .
im trying to Use Flutter Plugin :
flutter_numpad_widget
Here my Full code:
import 'package:flutter/material.dart';
import 'package:flutter_numpad_widget/flutter_numpad_widget.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
bool _confirmEnabled = false;
class _MyAppState extends State<MyApp> {
int maxRawLength;
final NumpadController _numpadController = NumpadController(
format: NumpadFormat.NONE,
hintText: "Ketikkan NIP",
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Numpad Example',
theme: ThemeData(
primarySwatch: Colors.amber,
buttonTheme: ButtonThemeData(
textTheme: ButtonTextTheme.normal,
buttonColor: Colors.blueGrey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30))))),
home: Scaffold(
appBar: AppBar(
title: Text('Numpad Example'),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: NumpadText(
style: TextStyle(fontSize: 30),
controller: _numpadController,
),
),
Expanded(
child: Numpad(
controller: _numpadController,
buttonTextSize: 40,
),
)
],
),
),
));
}
}
im following the documentation here :
onInputValidChange
but in this line its keep getting me Error "The instance member 'setState' can't be accessed in an initializer.":
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
im Already searching in few days and gets nothing.
thanks for your help priciateit
To add some explanation to your problem and I think in general is also valid:
You should init all your state properties in initState. If you have like bool flags or primitive properties that's fine but objects, in general, you should init in ```initState````. In your case:
import 'package:flutter/material.dart';
import 'package:flutter_numpad_widget/flutter_numpad_widget.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
bool _confirmEnabled = false;
class _MyAppState extends State<MyApp> {
int maxRawLength;
final NumpadController _numpadController; // this is the declaration
#override
void initState() {
super.initState();
_numpadController = NumpadController( // here is the init
format: NumpadFormat.NONE,
hintText: "Ketikkan NIP",
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Numpad Example',
theme: ThemeData(
primarySwatch: Colors.amber,
buttonTheme: ButtonThemeData(
textTheme: ButtonTextTheme.normal,
buttonColor: Colors.blueGrey[300],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30))))),
home: Scaffold(
appBar: AppBar(
title: Text('Numpad Example'),
),
body: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: NumpadText(
style: TextStyle(fontSize: 30),
controller: _numpadController,
),
),
Expanded(
child: Numpad(
controller: _numpadController,
buttonTextSize: 40,
),
)
],
),
),
));
}
}
You should declare your state inside The state widget like this:
class _MyAppState extends State<MyApp> {
int maxRawLength;
bool _confirmEnabled = false; // here
....
onInputValidChange: (bool valid) => setState(() {
_confirmEnabled = valid;
}),
...

Flutter app not keeping the settings made in the app after reopening the app

I have an app which has two tabs. One of the which is the "SAVED ITEMS" tab. When I save the items (from a different screen of ALL ITEMS LIST) it gets saved and on even switching the tabs works fine. But when I close the app and reopen it, the "SAVED ITEMS" list is empty and I've to select the items again. I've used the AutomaticKeepAliveClientMixin but its not helping. Any idea on how to solve this folks?
My code:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
super.build(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.blue,
accentColor: Colors.white,
),
home: DefaultTabController(
length: 2,
child: Scaffold(
drawer: Drawer(),
backgroundColor: Colors.blueAccent,
appBar: AppBar(
backgroundColor: Colors.blueAccent,
title: Text('AIO'),
bottom: TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.search)),
Tab(icon: Icon(Icons.favorite)),
],
),
),
body: TabBarView(
children: <Widget>[
gridView,
SecondPage(),
],
),
),
),
);
}
#override
bool get wantKeepAlive => true;
}
SecondTab code:
Set<int> favorites = {};
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage>
with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Stack(
fit: StackFit.expand,
children: <Widget>[
_getFavoriteList(),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.blue,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditFavorites(),
),
).then((updatedFavorites) {
if (updatedFavorites != null)
// setState(() {
favorites = updatedFavorites;
// });
});
},
),
),
)
],
);
}
Add shared_preferences dependency in pubspec.yaml
Update your main()
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences pref = await SharedPreferences.getInstance();
pref.getStringList("favorites")?.forEach((fav){
favorites.add(int.tryParse(fav));
});
runApp(MyApp());
}
then update your SecondPage
Set<int> favorites = {};
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
Future<void> _upDateFavorites(Set<int> updatedFavorites) async {
print("secong: u$updatedFavorites");
SharedPreferences pref = await SharedPreferences.getInstance();
List<String> favoritesAsString =
updatedFavorites.map((fav) => fav.toString()).toList(); //TODO: Change `favorites` to `updatedFavorites`
print(favoritesAsString);
await pref.setStringList("favorites", favoritesAsString); //TODO: await here to store it completely
favorites = updatedFavorites;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
_getFavoriteList(),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.blue,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditFavorites(),
),
).then((updatedFavorites) async {
if (updatedFavorites != null)
// setState(() {
_upDateFavorites(updatedFavorites);
// });
});
},
),
),
)
],
);
}
Widget _getFavoriteList() {
if (favorites?.isNotEmpty == true)
return _FavoriteList();
else
return _EmptyFavoriteList();
}
}
Don't forget to import 'package:shared_preferences/shared_preferences.dart'; where you use SharedPreferences
Avoid storing widget in a vaiable, if it needs to be rebuild.
So delete var favGridView = GridView.builder( ....
class _FavoriteList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: favorites.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
print("kkkkkkkkkkk: ${favorites.elementAt(index)}");
return InkWell(
child: Card(
elevation: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10),
child: Container(
child: Image.asset(
'lib/images/${images[favorites.elementAt(index)]}'), //TODO: Change this
// child: SizedBox(child: Text('yashjha'),),
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage('lib/images/${images[index]}'),
// fit: BoxFit.fitWidth,
// alignment: Alignment.topCenter,
// ),
// ),
),
),
Text(nameOfSite[favorites.elementAt(index)]), //TODO: Change This
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Text("dsadsa")),
);
},
);
},
);
}
}
I also recommend using actions instead of FloatingButton in _EditFavoritesState. Because the floating button hides last item. which makes it unable to add to favorites
AutomaticKeepAliveClientMixin is used to retain the data when the app is running and you need to retain data while switching between tabs, pages etc.
I would suggest you use SharedPreferences to easily save data to your memory that can be retrieved when the app is started again.
SharedPreferences: https://pub.dev/packages/shared_preferences

TextEditingController makes widget lose its previous state

When I use TextEditingController in CupertinoTextField, and change to another widget(page) and return, the previous state in that page is lost.
When I uncomment //controller: textController, everything works fine.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: DefaultTabController(
length: 2,
child: Scaffold(
body: TabBarView(
children: [new Search(), new Setting(),
],
),
bottomNavigationBar: Container(
height: 60,
child: new TabBar(
tabs: [
Tab(icon: new Icon(Icons.search)),
Tab(icon: new Icon(Icons.settings)),
],
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
),
)
),
),
);
}
}
class Setting extends StatelessWidget {
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.check),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(
builder: (context) =>
new Scaffold(
appBar: AppBar(title: Text('3'),),
)));
});
}
}
class Search extends StatefulWidget {
#override
createState() => new SearchState();
}
class SearchState extends State<Search> {
String currentWord = '';
final TextEditingController textController = new TextEditingController();
#override
void dispose() {
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Row(
children: <Widget>[
new Expanded(
child: new CupertinoTextField(
style: TextStyle(color: Colors.white),
cursorColor: Colors.white,
//controller: textController,
maxLines: 1,
clearButtonMode: OverlayVisibilityMode.editing,
onChanged: (text) {
setState(() {
currentWord = text;
});
},
),
),
],
),
),
body: ListView.builder(
itemCount: 5,
itemBuilder: (context, i) {
return Text(currentWord);
})
);
}
}
The expected result(without controller set):get back and the state keeps the same.
Actual results(with controller set): get back and the state lost
The explanation for the observed behavior is the following:
CupertinoTextField uses an internal TextEditingController for which the framework automatically sets an AutomaticKeepAlive. This keepAlive is responsible for keeping the state.
If you use your own controller, you are in charge of attaching the AutomaticKeepAlive because the framework doesn't do it for you.
The following snippet adds the keepAlive to your code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: DefaultTabController(
length: 2,
child: Scaffold(
body: TabBarView(
children: [
new Search(),
new Setting(),
],
),
bottomNavigationBar: Container(
height: 60,
child: new TabBar(
tabs: [
Tab(icon: new Icon(Icons.search)),
Tab(icon: new Icon(Icons.settings)),
],
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
),
)),
),
);
}
}
class Setting extends StatelessWidget {
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.check),
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => new Scaffold(
appBar: AppBar(
title: Text('3'),
),
)));
});
}
}
class Search extends StatefulWidget {
#override
createState() => new SearchState();
}
class SearchState extends State<Search> with AutomaticKeepAliveClientMixin {
String currentWord = '';
final TextEditingController textController = new TextEditingController();
#override
void initState() {
super.initState();
textController?.addListener(updateKeepAlive);
}
#override
void dispose() {
textController?.removeListener(updateKeepAlive);
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context); // See AutomaticKeepAliveClientMixin.
return new Scaffold(
appBar: new AppBar(
title: new Row(
children: <Widget>[
new Expanded(
child: new CupertinoTextField(
style: TextStyle(color: Colors.white),
cursorColor: Colors.white,
controller: textController,
maxLines: 1,
clearButtonMode: OverlayVisibilityMode.editing,
onChanged: (text) {
setState(() {
currentWord = text;
});
},
),
),
],
),
),
body: ListView.builder(
itemCount: 5,
itemBuilder: (context, i) {
return Text(currentWord);
}));
}
#override
bool get wantKeepAlive => textController?.text?.isNotEmpty == true;
}

Categories

Resources