为何CustomPaint置于Scaffold下时会失去缩放不变性?
场景1:App〈MaterialApp〈MyWidget:一切正常
无论将画布上的图形以大比例还是小比例绘制——将代码中的v = 100000.0替换为v = 1000.0,图像均不会发生变化,符合预期。
(如果不熟悉在FittedBox内使用SizedBox的布局思路,可参考相对尺寸适配逻辑)

import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); const v = 10000.0; class Painter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final mypaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 0.012 * v ..color = Colors.blue; canvas.drawCircle( Offset(1.5 * v, 1 * v), 1 * v, mypaint); } @override bool shouldRepaint(Painter oldDelegate) => false; } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: "My App", home: FittedBox( child: SizedBox( width: 3 * v, height: 2 * v, child: CustomPaint( painter: Painter() ), ), ), ); } }
场景2:App〈Scaffold〈MaterialApp〈MyWidget:为何SizedBox的自定义尺寸被忽略?
但如果将MaterialApp置于Scaffold内,当v = 10000.0时仍显示左侧图像,而v = 100.0时则显示右侧图像。

import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); const v = 10000.0; class Painter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final mypaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 0.012 * v ..color = Colors.blue; canvas.drawCircle( Offset(1.5 * v, 1 * v), 1 * v, mypaint); } @override bool shouldRepaint(Painter oldDelegate) => false; } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: "My App", home: Scaffold( appBar: AppBar( title: const Text('My Title'), ), body: FittedBox( child: SizedBox( width: 3 * v, height: 2 * v, child: CustomPaint( painter: Painter() ), ), ), ), ); } }
问题:如何在包含Scaffold的布局中实现缩放不变的CustomPaint?
解决方案
问题根源是Scaffold的body会默认约束子组件的最大尺寸为可用空间,导致FittedBox的缩放逻辑被干扰。可通过以下两种方式解决:
方法1:解除FittedBox的尺寸约束
将FittedBox包裹在UnconstrainedBox中,摆脱Scaffold的尺寸限制,让FittedBox完全基于SizedBox的原始尺寸进行缩放:
body: UnconstrainedBox( child: FittedBox( child: SizedBox( width: 3 * v, height: 2 * v, child: CustomPaint(painter: Painter()), ), ), )
方法2:基于组件尺寸进行相对绘制
放弃固定的v值,改用CustomPaint的size参数做相对计算,让图形比例完全适配组件自身尺寸,不受外部布局影响:
class Painter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final mypaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 0.012 * size.width // 基于宽度的相对描边 ..color = Colors.blue; // 以画布中心为圆心,半径取宽度的1/3 canvas.drawCircle( Offset(size.width / 2, size.height / 2), size.width / 3, mypaint ); } @override bool shouldRepaint(Painter oldDelegate) => false; }
这种方式更灵活,无需依赖外部变量,无论嵌套多少层布局都能保持缩放一致性。
内容的提问来源于stack exchange,提问作者Sam7919
相关产品推荐
相关产品推荐

