如何修复 flutter 中小屏幕尺寸的缩放?

How fix scaling for small screen size in 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), // changes position of shadow
                        ),
                      ],
                      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), // changes position of shadow
                        ),
                      ],
                      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), // changes position of shadow
                        ),
                      ],
                      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), // changes position of shadow
                        ),
                      ],
                      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), // changes position of shadow
                    ),
                  ],
                  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), // <-- Radius
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

提供的屏幕截图声明了更多详细信息:

许多可能的解决方案:

  • 通过 SingleChildScrollView 包装您的 Column 小部件
  • 用可滚动小部件替换列
  • 使用“环绕”小部件而不是“列”小部件

SafeArea( /// controlls the reset of space
        bottom: false,
        child: Container( /// define the child height witch breaks the SafeArea physics
          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( /// the child you gonna to update with above possabilities

--更新--

正如您在有关缩放小部件的评论中提到的,据我所知有两种方法

首先,您可以使用 flutter_screenutil

其次,您可以像我一样创建自己的尺码服务

import 'package:flutter/widgets.dart';
import 'package:get/get.dart';


class SizeConfig {
  
  /// create singleton instance
  SizeConfig._internal();
  static final SizeConfig _instance = SizeConfig._internal();
  factory SizeConfig() => _instance;


  double screenWidth = Get.context.orientation == Orientation.portrait ? Get.mediaQuery.size.width : Get.mediaQuery.size.height;

  double screenHeight = Get.context.orientation == Orientation.portrait ? Get.mediaQuery.size.height : Get.mediaQuery.size.width;

  double infinityHeight() => double.infinity;

  double infinityWidth() => double.infinity;

  double blockSizeHorizontal() => screenWidth / 100;

  double blockSizeVertical() => screenHeight / 100;

  double _safeAreaHorizontal() => Get.mediaQuery.padding.left + Get.mediaQuery.padding.right;

  double _safeAreaVertical() => Get.mediaQuery.padding.top + Get.mediaQuery.padding.bottom;

  double safeBlockHorizontal() => (screenWidth - (Get.context.orientation == Orientation.portrait ? _safeAreaHorizontal() : _safeAreaVertical())) / 100;

  double safeBlockVertical() => (screenHeight - (Get.context.orientation == Orientation.portrait ? _safeAreaVertical() : _safeAreaHorizontal())) / 100;

  double fontSize50() => safeBlockHorizontal() * 5.0;
  double fontSize51() => safeBlockHorizontal() * 5.1;
  double fontSize52() => safeBlockHorizontal() * 5.2;
  double fontSize53() => safeBlockHorizontal() * 5.3;
  double fontSize54() => safeBlockHorizontal() * 5.4;
  double fontSize55() => safeBlockHorizontal() * 5.5;
  double fontSize56() => safeBlockHorizontal() * 5.6;
  double fontSize57() => safeBlockHorizontal() * 5.7;
  double fontSize58() => safeBlockHorizontal() * 5.8;
  double fontSize59() => safeBlockHorizontal() * 5.9;
}

我将此 SizeConfig() 服务与 GetX 一起使用,并将其用作

width: SizeConfig().safeBlockHorizontal() * 10, // 10% from screen width

height: SizeConfig().safeBlockVertical() * 10 // 10% from screen height