实际上,我尝试实现一个计时器。定制画家结果还不错。但是,当我尝试将自定义画家放在行或列中时,它会溢出。仅当我明确定义容器的高度和宽度时,才会显示自定义绘画。现在,我需要在行中添加一个带有自定义绘画的计时器字符串,但是它不起作用。容器的高度和宽度占整个屏幕的大小,不允许显示任何其他小部件。
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Styles.primaryDarkBlue,
body: SafeArea(
child: Container(
height: height,
width: width,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CustomPaint(
painter: TimerBar(
animation: animation,
)),
),
),
));
}
这里是完整代码。
import 'package:flutter/material.dart';
import 'package:focus7/styles.dart';
class Timer extends StatefulWidget {
@override
_TimerState createState() => _TimerState();
}
class _TimerState extends State<Timer> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation animation;
String get timerString {
Duration duration = controller.duration * controller.value;
return "${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, "0")}";
}
@override
void initState() {
super.initState();
controller = AnimationController(vsync: this, duration: Duration(seconds: 7));
animation = Tween<double>(begin: 0.1, end: 1).animate(controller);
controller.forward();
}
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
print(height);
return Scaffold(
backgroundColor: Styles.primaryDarkBlue,
body: SafeArea(
child: Container(
height: height,
width: width,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CustomPaint(
painter: TimerBar(
animation: animation,
)),
),
),
));
}
}
class TimerBar extends CustomPainter {
final Gradient gradient = Styles.primaryGradient;
final Color timerBarColor = Styles.primaryBlue;
final Animation animation;
TimerBar({this.animation}) : super(repaint: animation);
@override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = timerBarColor
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 5;
Rect rect = new Rect.fromLTWH(0, 0, size.width, size.height / 25);
RRect rrectBorder = new RRect.fromRectAndRadius(rect, Radius.circular(50));
canvas.drawRRect(rrectBorder, paint);
paint.style = PaintingStyle.fill;
paint.strokeWidth = 0;
paint.shader = gradient.createShader(rect);
Rect rectAnim = new Rect.fromLTWH(0, 0, size.width * animation.value, size.height / 25);
RRect rrect = new RRect.fromRectAndRadius(rectAnim, Radius.circular(50));
canvas.drawRRect(rrect, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return false;
}
}
这里是输出:
当我尝试嵌套时:
return Scaffold(
backgroundColor: Styles.primaryDarkBlue,
body: SafeArea(
child: Row(
children: <Widget>[
Container(
height: height,
width: width,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CustomPaint(
painter: TimerBar(
animation: animation,
)),
),
),
AnimatedBuilder(animation: controller, builder: (context, child) {
return Text(timerString,style: TextStyle(fontSize:24 ),);
})
],
),
));
这可以通过扩展窗口小部件来完成,并将宽度和高度显式传递给Timer()类。
我使用代码创建了此dartpad,以便您可以运行它(我必须更改某些样式才能使其起作用):http://dartpad.dev/eb69452a5c577d1a8286c6dd1a56e331
首先,我在脚手架中使用的扩展小部件:
return Scaffold(
backgroundColor: Colors.yellow,
body: SafeArea(
child: Row(
children: <Widget>[
Expanded( // <----------------------------------
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CustomPaint(
painter: TimerBar(
width: width,
height: height,
animation: animation,
),
),
),
),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Text(
timerString,
style: TextStyle(fontSize: 24),
);
},
)
],
),
),
);
这很有效,但是计时器栏的高度和宽度没有根据mediaquery调整大小,因此我将显式变量传递给该类:
class TimerBar extends CustomPainter {
final Gradient gradient = LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.blue, Colors.red]);
final Color timerBarColor = Colors.blue;
final Animation animation;
final width; // <----------------------------------
final height; // <----------------------------------
TimerBar({this.animation, this.width, this.height}) // <----------------
: super(repaint: animation);
...
然后我将这些宽度用于您的两个矩形对象:
Rect rect = new Rect.fromLTWH(0, 0, width, height / 25); // <-------------
RRect rrectBorder = new RRect.fromRectAndRadius(rect, Radius.circular(50));
canvas.drawRRect(rrectBorder, paint);
paint.style = PaintingStyle.fill;
paint.strokeWidth = 0;
paint.shader = gradient.createShader(rect);
Rect rectAnim =
new Rect.fromLTWH(0, 0, width * animation.value, height / 25); // <------------
RRect rrect = new RRect.fromRectAndRadius(rectAnim, Radius.circular(50));
经过多次尝试和错误,我找到了解决方案。...下面的代码看起来不错。
return Scaffold(
backgroundColor: Styles.primaryDarkBlue,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return CustomPaint(painter: TimerBar(animation: animation, height: height));
}),
),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Text(
timerString,
style: TextStyle(fontSize: 24, color: Styles.primaryWhite),
);
}),
),
)
],
),
),
));
输出: