Проблема: я могу создавать упражнения и добавлять их в анимированный список в CustomExScreen.
Когда я возвращаюсь на предыдущий уровень стека, будучи MenuScreen (), а затем повторно посещаю мой список упражнений, мои ранее отправленные данные удаляются. , Как сохранить состояние данных даже при выходе из виджета? Сохраните стек и восстановите его. Заранее спасибо!
CustomExScreenState
class CustomExScreen extends StatefulWidget {
@override
CustomExScreenState createState() => CustomExScreenState();
}
class CustomExScreenState extends State<CustomExScreen>
with TickerProviderStateMixin {
List<Exerciselist> items = new List<Exerciselist>();
GlobalKey<AnimatedListState> animatedListKey = GlobalKey<AnimatedListState>();
AnimationController emptyListController;
@override
void initState() {
emptyListController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
);
emptyListController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'CUSTOM EXERCISES',
key: Key('main-app-title'),
),
centerTitle: true,
),
floatingActionButton: Container(
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => goToNewItemView(),
),
),
body: renderBody(),
);
}
Widget renderBody() {
if (items.length > 0) {
return buildListView();
} else {
return emptyList();
}
}
Widget emptyList() {
return Center(
child: FadeTransition(
opacity: emptyListController,
child: Text('No exercise, press + to add some!')));
}
Widget buildListView() {
return AnimatedList(
key: animatedListKey,
initialItemCount: items.length,
itemBuilder: (BuildContext context, int index, animation) {
setState(() {
buildItem(items[index], index);
});
return SizeTransition(
sizeFactor: animation,
child: buildItem(items[index], index),
);
},
);
}
Widget buildItem(Exerciselist item, int index) {
return Dismissible(
key: Key('${item.hashCode}'),
background: Container(color: Colors.red[700]),
onDismissed: (direction) => removeItemFromList(item, index),
direction: DismissDirection.startToEnd,
child: buildListTile(item, index),
);
}
Widget buildListTile(item, index) {
return ListTile(
onTap: () => changeItemCompleteness(item),
onLongPress: () => goToEditItemView(item),
title: Text(
item.title,
key: Key('item-$index'),
style: TextStyle(
color: item.completed ? Colors.grey : Colors.black,
decoration: item.completed ? TextDecoration.lineThrough : null),
),
trailing: Icon(
item.completed ? Icons.check_box : Icons.check_box_outline_blank,
key: Key('completed-icon-$index'),
),
);
}
void changeItemCompleteness(Exerciselist item) {
setState(() {
item.completed = !item.completed;
});
}
void goToNewItemView() {
// Here we are pushing the new view into the Navigator stack. By using a
// MaterialPageRoute we get standard behaviour of a Material app, which will
// show a back button automatically for each platform on the left top corner
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return NewCustomExercise();
})).then((title) {
if (title != null) {
addItem(Exerciselist(title: title));
}
});
}
void addItem(Exerciselist item) {
// Insert an item into the top of our list, on index zero
items.insert(0, item);
if (animatedListKey.currentState != null)
animatedListKey.currentState.insertItem(0);
}
void goToEditItemView(Exerciselist item) {
// We re-use the NewTodoView and push it to the Navigator stack just like
// before, but now we send the title of the item on the class constructor
// and expect a new title to be returned so that we can edit the item
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return NewCustomExercise(item: item);
})).then((title) {
if (title != null) {
editItem(item, title);
}
});
}
void editItem(Exerciselist item, String title) {
item.title = title;
}
void removeItemFromList(Exerciselist item, int index) {
animatedListKey.currentState.removeItem(index, (context, animation) {
return SizedBox(
width: 0,
height: 0,
);
});
deleteItem(item);
}
void deleteItem(Exerciselist item) {
// We don't need to search for our item on the list because Dart objects
// are all uniquely identified by a hashcode. This means we just need to
// pass our object on the remove method of the list
items.remove(item);
if (items.isEmpty) {
emptyListController.reset();
setState(() {});
emptyListController.forward();
}
}
}
Exerciselist
class Exerciselist {
String title;
bool completed;
Exerciselist({
this.title,
this.completed = false,
});
Exerciselist.fromMap(Map<String, dynamic> map)
: title = map['title'],
completed = map['completed'];
updateTitle(title) {
this.title = title;
}
Map toMap() {
return {
'title': title,
'completed': completed,
};
}
}
MenuScreen
class MenuScreen extends StatefulWidget {
@override
_MenuScreenState createState() => _MenuScreenState();
}
class _MenuScreenState extends State<MenuScreen> {
int difficulty = 2;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kBackgroundColour,
appBar: AppBar(
backgroundColor: kButtonAndBarColour,
title: Text('COVID-19 WORKOUTS', style: kTitleStyle),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
RaisedButton(
elevation: 100.0,
color: kButtonAndBarColour,
child: Text('CARDIO', style: kTitleStyle),
onPressed: () {
//NEED TO UPDATE STATE AND HAVE NEW DATA FOR CARDIO SCREEN
FeedDifficulty cardioDifficulty =
FeedDifficulty(difficulty: difficulty);
GenerateCardio generateCardio =
GenerateCardio(difficulty: difficulty);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CardioScreen(
cardioDifficulty:
cardioDifficulty.checkDifficulty(),
cardioWorkout1: generateCardio.cExerciseOne(),
cardioWorkout2: generateCardio.cExerciseTwo(),
cardioWorkout3: generateCardio.cExerciseThree(),
cardioWorkout4: generateCardio.cExerciseFour(),
cardioWorkout5: generateCardio.cExerciseFive(),
)),
);
print('Cardio Pressed');
},
),
SizedBox(
height: 20.0,
),
RaisedButton(
elevation: 100.0,
color: kButtonAndBarColour,
child: Text(
'STRENGTH & ENDURANCE',
style: kTitleStyle,
),
onPressed: () {
FeedDifficulty strengthWorkout =
FeedDifficulty(difficulty: difficulty);
GenerateStrength generateStrength =
GenerateStrength(difficulty: difficulty);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StrengthScreen(
strengthDifficulty: strengthWorkout.checkDifficulty(),
strengthWorkout1: generateStrength.sExerciseOne(),
strengthWorkout2: generateStrength.sExerciseTwo(),
strengthWorkout3: generateStrength.sExerciseThree(),
strengthWorkout4: generateStrength.sExerciseFour(),
strengthWorkout5: generateStrength.sExerciseFive(),
),
),
);
// Navigator.pushNamed(context, '/strength');
print('Strength Pressed');
},
),
RaisedButton(
elevation: 100.0,
color: kButtonAndBarColour,
child: Text(
'CUSTOM WORKOUT',
style: kTitleStyle,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return CustomExScreen(
//construct
);
}));
// Navigator.pushNamed(context, '/strength');
print('CUSTOM Pressed');
},
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
inactiveTrackColor: Color(0xFF8D8E98),
activeTrackColor: Colors.white,
thumbColor: Color(0xFFEB1555),
overlayColor: Color(0x29EB1555),
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape: RoundSliderOverlayShape(overlayRadius: 30),
),
child: Slider(
value: difficulty.toDouble(),
min: 1.0,
max: 3.0,
onChanged: (double newValue) {
setState(() {
difficulty = newValue.round();
print(difficulty);
});
},
),
),
Text(
difficulty.toString(),
style: kTitleStyleDark,
),
SizedBox(height: 8.0),
Text(
'DIFFICULTY',
style: kTitleStyleDark,
),
],
),
),
);
}
}