用于保存不同页面状态的代码如下:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:workouttimer/view/TimerView.dart';
import 'package:workouttimer/view/IntervalTimerView.dart';
void main() => runApp(MaterialApp(
home: Home(),
theme: ThemeData(
canvasColor: Colors.blueGrey,
iconTheme: IconThemeData(
color: Colors.white,
),
accentColor: Colors.pinkAccent,
brightness: Brightness.dark,
),
));
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final List<Widget> pages = [
TimerView(
key: PageStorageKey('Timer'),
),
IntervalTimerView(
key: PageStorageKey('Interval Timer'),
),
];
final PageStorageBucket bucket = PageStorageBucket();
int _selectedIndex = 0;
Widget _bottomNavigationBar(int selectedIndex) => BottomNavigationBar(
onTap: (int index) => setState(() => _selectedIndex = index),
currentIndex: selectedIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.av_timer), title: Text('Timer')),
BottomNavigationBarItem(
icon: Icon(Icons.timer), title: Text('Interval Timer')),
],
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Workout Timer", style: TextStyle(
color: Colors.white
)),
leading: GestureDetector(
onTap: () => exit(0),
child: Icon(
Icons.exit_to_app, // add custom icons also
),
),
centerTitle: true,
backgroundColor: Colors.orange,),
bottomNavigationBar: _bottomNavigationBar(_selectedIndex),
body: PageStorage(
child: pages[_selectedIndex],
bucket: bucket,
),
);
}
}
计时器页面的代码是这样的:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'dart:math' as math;
import 'package:flutter/services.dart';
class TimerView extends StatefulWidget {
const TimerView({Key key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<TimerView> with TickerProviderStateMixin {
AnimationController controller;
int time = 10;
List<AnimationController> listOfTimer = [];
List<int> listOfTiming = [];
List<String> listOfDisplayTiming = [];
bool loading = true;
String get timerString {
Duration duration = controller.duration * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
loadJson() async {
String data = await rootBundle.loadString('assets/timer_data.json');
var jsonResult = json.decode(data);
for (int i=0; i<jsonResult.length;i ++){
listOfTiming.add(jsonResult[i]);
}
for (int i=0; i<listOfTiming.length;i ++){
controller = AnimationController(
vsync: this,
duration: Duration(seconds: listOfTiming[i]),
);
listOfTimer.add(controller);
}
setState(() {
});
}
@override
void initState() {
loadJson();
super.initState();
}
@override
Widget build (BuildContext context) {
return Scaffold(
body:ListView.builder
(
itemCount: listOfTimer.length ,
itemBuilder: (BuildContext context, int index) {
return _listItem(index);
}
)
);
}
_listItem(index) {
return Card(
color: Colors.white70,
child: Container(
height: MediaQuery.of(context).size.height / 3.65,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Positioned.fill(
child: AnimatedBuilder(
animation: listOfTimer[index],
builder: (BuildContext context, Widget child) {
// the display of pink countdown circle
return CustomPaint(
painter: TimerPainter(
animation: listOfTimer[index],
backgroundColor: Colors.black,
color: Colors.orange,
),
willChange: true,
);
},
),
),
Column(
// the display of timer countdown
children: <Widget>[
Text(
"Timer",
style: TextStyle(fontSize: 15,
color: Colors.black,
),
),
AnimatedBuilder(
animation: listOfTimer[index],
builder: (BuildContext context, Widget child) {
return Countdown(
animation: StepTween(
begin: listOfTiming[index],
end: 0,
).animate(listOfTimer[index]),
);
}),
],
),
],
),
Container(
child: Row(
children: <Widget>[
FloatingActionButton(
child: AnimatedBuilder(
animation: listOfTimer[index],
builder: (BuildContext context, Widget child) {
return Icon(listOfTimer[index].isAnimating
? Icons.pause
: Icons.play_arrow,
color: Colors.black,
);
// Icon(isPlaying
// ? Icons.pause
// : Icons.play_arrow);
},
),
onPressed: () {
// setState(() => isPlaying = !isPlaying);
if (listOfTimer[index].isAnimating) {
listOfTimer[index].stop(canceled: true);
} else {
listOfTimer[index].reverse(
from: listOfTimer[index].value == 0.0
? 1.0
: listOfTimer[index].value);
}
},
backgroundColor: Colors.orange,
)
],
),
)
],
),
),
),
);
}
}
class TimerPainter extends CustomPainter {
TimerPainter({
this.animation,
this.backgroundColor,
this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 5.0
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & Size(size.width, size.width), math.pi * 1.5, progress, false, paint);
}
@override
bool shouldRepaint(TimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
class Countdown extends AnimatedWidget {
Countdown({Key key, this.animation}) : super(key: key, listenable: animation);
Animation<int> animation;
@override
build(BuildContext context) {
Duration clockTimer = Duration(seconds: animation.value);
String timerText =
'${clockTimer.inMinutes.remainder(60).toString()}:${clockTimer.inSeconds.remainder(60).toString().padLeft(2, '0')}';
return Text(
"$timerText",
style: TextStyle(
fontSize: 40,
color: Colors.black,
),
);
}
}
我遇到的问题是,当我移至另一页时,计时器和滚动轴的状态将无法保存。它将始终重新启动页面并切换到最顶部。关于如何保存状态的任何想法吗?