You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何修复小屏幕尺寸下的UI缩放适配异常问题

Flutter多屏幕适配问题修复

问题说明

  • 开发目标:适配不同尺寸的屏幕
  • 故障表现:界面UI在不同设备上显示效果异常,出现UI报错。在iPhone 13模拟器上所有元素显示正常,但在屏幕分辨率为1280x768的智能手机上运行时,界面完全崩坏。

相关代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'auth.dart';

void main() {
  runApp(const Auth());
}

class Main extends StatelessWidget {
  const Main({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: const MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        toolbarHeight: 0,
      ),
      backgroundColor: const Color.fromARGB(255, 247, 255, 247),
      body: SafeArea(
        bottom: false,
        child: Container(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          decoration: const BoxDecoration(
            image: DecorationImage(
              alignment: Alignment.bottomCenter,
              image: AssetImage('assets/images/spikelets.png'),
              fit: BoxFit.fitWidth,
            ),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Stack(
                children: [
                  Container(
                      alignment: Alignment.topLeft,
                      margin: EdgeInsets.only(top: 35, left: 49),
                      child: Text(
                        'Добро',
                        style: TextStyle(
                          fontFamily: 'GoodVibesCyr',
                          fontSize: 92,
                          color: Colors.green,
                        ),
                      )),
                  Container(
                      alignment: Alignment.topLeft,
                      margin: EdgeInsets.only(top: 100, left: 35),
                      child: Text(
                        'пожаловать!',
                        style: TextStyle(
                          fontFamily: 'TTCommons',
                          fontSize: 54,
                          color: Colors.green,
                          fontWeight: FontWeight.bold,
                        ),
                      )),
                ],
              ),
              Container(
                alignment: Alignment.topLeft,
                margin: EdgeInsets.only(top: 20, left: 25),
                child: Text(
                  'Мобильный заказ',
                  style: TextStyle(
                    fontFamily: 'TTCommons',
                    fontWeight: FontWeight.bold,
                    fontSize: 36,
                    color: Colors.black,
                  ),
                ),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    height: 150,
                    width: 150,
                    margin: EdgeInsets.only(top: 15),
                    decoration: const BoxDecoration(
                      image: DecorationImage(
                        alignment: Alignment.bottomCenter,
                        image: AssetImage(
                            'assets/images/backgroundMainButtons.png'),
                        fit: BoxFit.fitWidth,
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Color.fromARGB(41, 0, 0, 0),
                          blurRadius: 6,
                          offset: Offset(0, 3),
                        ),
                      ],
                      borderRadius: BorderRadius.all(Radius.circular(20)),
                    ),
                  ),
                  Container(
                    height: 150,
                    width: 150,
                    margin: EdgeInsets.only(left: 25, top: 15),
                    decoration: const BoxDecoration(
                      image: DecorationImage(
                        alignment: Alignment.bottomCenter,
                        image: AssetImage(
                            'assets/images/backgroundMainButtons.png'),
                        fit: BoxFit.fitWidth,
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Color.fromARGB(41, 0, 0, 0),
                          blurRadius: 6,
                          offset: Offset(0, 3),
                        ),
                      ],
                      borderRadius: BorderRadius.all(Radius.circular(20)),
                    ),
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    height: 150,
                    width: 150,
                    margin: EdgeInsets.only(top: 15),
                    decoration: const BoxDecoration(
                      image: DecorationImage(
                        alignment: Alignment.bottomCenter,
                        image: AssetImage(
                            'assets/images/backgroundMainButtons.png'),
                        fit: BoxFit.fitWidth,
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Color.fromARGB(41, 0, 0, 0),
                          blurRadius: 6,
                          offset: Offset(0, 3),
                        ),
                      ],
                      borderRadius: BorderRadius.all(Radius.circular(20)),
                    ),
                  ),
                  Container(
                    height: 150,
                    width: 150,
                    margin: EdgeInsets.only(left: 25, top: 15),
                    decoration: const BoxDecoration(
                      image: DecorationImage(
                        alignment: Alignment.bottomCenter,
                        image: AssetImage(
                            'assets/images/backgroundMainButtons.png'),
                        fit: BoxFit.fitWidth,
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Color.fromARGB(41, 0, 0, 0),
                          blurRadius: 6,
                          offset: Offset(0, 3),
                        ),
                      ],
                      borderRadius: BorderRadius.all(Radius.circular(20)),
                    ),
                  ),
                ],
              ),
              Container(
                margin: EdgeInsets.only(top: 15, right: 15),
                width: 325,
                height: 60,
                decoration: BoxDecoration(
                  boxShadow: [
                    BoxShadow(
                      color: Color.fromARGB(255, 67, 152, 71),
                      blurRadius: 0,
                      offset: Offset(0, 10),
                    ),
                  ],
                  borderRadius: BorderRadius.all(Radius.circular(20)),
                ),
                child: SizedBox(
                  width: 325,
                  height: 60,
                  child: ElevatedButton(
                    onPressed: () {},
                    child: Text(
                      'Товары недели',
                      style: TextStyle(
                          fontFamily: 'TTCommons',
                          fontSize: 32,
                          fontWeight: FontWeight.bold),
                    ),
                    style: ElevatedButton.styleFrom(
                      alignment: Alignment.center,
                      shadowColor: Color.fromARGB(0, 0, 0, 0),
                      padding: EdgeInsets.all(15),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

问题根因

现有代码所有尺寸参数均使用固定硬编码像素值,未做响应式适配:

  • 字体大小、容器宽高、边距margin全部为固定数值,不同屏幕的宽度、像素密度、宽高比存在差异,小屏设备上内容会超出屏幕边界
  • 布局根容器使用Column但未添加滚动能力,内容总高度超出屏幕高度时直接触发溢出报错

修复方案

  1. 统一使用相对尺寸计算
    在build方法中先获取当前屏幕参数,以设计稿基准尺寸计算缩放比例,所有数值都乘以缩放比例实现自适应:
@override
Widget build(BuildContext context) {
  // 新增尺寸计算逻辑,假设设计稿基准宽度为375px
  final screenWidth = MediaQuery.of(context).size.width;
  final scale = screenWidth / 375;
  // 原有逻辑
  return Scaffold(
    // ...
  );
}

所有固定数值按比例替换:

  • 字体大小:fontSize: 92 改为 fontSize: 92 * scale
  • 卡片宽高:width: 150, height:150 改为 width: 150 * scale, height: 150 * scale
  • 边距:EdgeInsets.only(top: 35, left: 49) 改为 EdgeInsets.only(top: 35 * scale, left: 49 * scale)
  • 按钮宽度:width: 325 改为 width: screenWidth * 0.85
  1. 新增滚动能力避免溢出
    将Column外层包裹SingleChildScrollView,小屏设备内容超出高度时可滚动查看,不会触发溢出报错:
child: Container(
  width: MediaQuery.of(context).size.width,
  height: MediaQuery.of(context).size.height,
  decoration: const BoxDecoration(
    image: DecorationImage(
      alignment: Alignment.bottomCenter,
      image: AssetImage('assets/images/spikelets.png'),
      fit: BoxFit.fitWidth,
    ),
  ),
  // 新增SingleChildScrollView
  child: SingleChildScrollView(
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        // 原有Column子组件
      ],
    ),
  )
)
  1. 可选优化:使用第三方适配库
    如果项目复杂度较高,可直接引入flutter_screenutil等成熟适配库,自动处理尺寸缩放逻辑,无需手动计算比例。

内容的提问来源于stack exchange,提问作者Alexander Avanesyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:24:05