如何基于Figma固定像素值打造适配多移动端的Flutter响应式UI?
基于Figma固定像素的Flutter全端响应式UI适配方案
核心思路
Figma给出的是物理像素,Flutter使用逻辑像素,适配的核心是建立物理像素到逻辑像素的映射关系,同时区分两类元素:
- 可完全按比例缩放的元素:容器间距、普通图标、大部分布局尺寸
- 需要保留最小尺寸的元素:TextField、按钮、小图标(避免小屏上缩得无法交互)
推荐方案及实践
1. 优化使用flutter_screenutil(第三方包)
你之前用这个包适配效果不佳,问题在于没区分元素类型直接全量缩放,导致TextField过小。优化要点:
- 初始化时严格对应Figma的设计稿尺寸
- 文字用
sp单位而非普通fontSize - 给TextField、按钮等交互元素设置最小尺寸约束
初始化代码:
void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return ScreenUtilInit( // 替换为你的Figma设计稿宽高(物理像素) designSize: const Size(375, 812), minTextAdapt: true, // 开启文字自适应 splitScreenMode: true, // 支持分屏场景适配 builder: (context, child) { return MaterialApp( debugShowCheckedModeBanner: false, title: '适配Demo', theme: ThemeData(primarySwatch: Colors.blue), home: child, ); }, child: const HomePage(), ); } }
TextField适配示例:
TextField( decoration: InputDecoration( hintText: '请输入内容', contentPadding: EdgeInsets.symmetric( horizontal: 16.w, // 水平内边距按比例缩放 vertical: 12.h, // 垂直内边距按比例缩放 ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), // 圆角按比例缩放 borderSide: BorderSide(width: 1.w), // 边框宽度按比例缩放 ), ), style: TextStyle(fontSize: 14.sp), // 文字用sp单位适配 // 限制最小宽度,避免小屏上缩得太窄 minWidth: 200.w, maxWidth: double.infinity, )
2. 原生MediaQuery+LayoutBuilder方案(无依赖)
如果不想依赖第三方包,可自行封装适配工具类,核心是计算屏幕与设计稿的缩放比例:
适配工具类:
class AdaptUtil { static late Size _designSize; // Figma设计稿尺寸 static late double _scaleWidth; static late double _scaleHeight; static late double _scaleText; // 初始化:传入上下文和设计稿尺寸 static void init(BuildContext context, {Size designSize = const Size(375, 812)}) { _designSize = designSize; final screenSize = MediaQuery.of(context).size; _scaleWidth = screenSize.width / _designSize.width; _scaleHeight = screenSize.height / _designSize.height; // 文字取宽高比例的最小值,避免长屏上文字过大 _scaleText = _scaleWidth > _scaleHeight ? _scaleHeight : _scaleWidth; } // 宽度适配方法 static double w(double value) => value * _scaleWidth; // 高度适配方法 static double h(double value) => value * _scaleHeight; // 文字大小适配方法 static double sp(double value) => value * _scaleText; }
使用示例:
class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { // 初始化适配工具 AdaptUtil.init(context); return Scaffold( body: Padding( padding: EdgeInsets.all(AdaptUtil.w(16)), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( decoration: InputDecoration( hintText: '请输入内容', contentPadding: EdgeInsets.symmetric( horizontal: AdaptUtil.w(16), vertical: AdaptUtil.h(12), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(AdaptUtil.w(8)), borderSide: BorderSide(width: AdaptUtil.w(1)), ), ), style: TextStyle(fontSize: AdaptUtil.sp(14)), minWidth: AdaptUtil.w(200), maxWidth: double.infinity, ), SizedBox(height: AdaptUtil.h(20)), ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric( horizontal: AdaptUtil.w(32), vertical: AdaptUtil.h(12), ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AdaptUtil.w(8)), ), ), child: Text( '提交', style: TextStyle(fontSize: AdaptUtil.sp(16)), ), ), ], ), ), ); } }
关键注意事项
- 区分元素类型:交互元素(TextField、按钮)必须设置最小尺寸,避免小屏上无法点击或输入;布局元素(间距、容器)可完全按比例缩放。
- 文字适配优先级:文字缩放取宽高比例的最小值,保证在长屏或宽屏上文字不会过大或过小。
- 测试多设备:用Flutter DevTools的设备预览功能,测试不同分辨率、屏幕比例的设备,确保布局不崩溃。
- 避免过度缩放:对于极小图标(如20px以下),可设置固定尺寸,或限制缩放后的最小尺寸(比如
max(AdaptUtil.w(20), 16))。
内容的提问来源于stack exchange,提问作者Ramesh Raja
相关产品推荐
相关产品推荐

