flutter 屏幕适配分析

  • Post author:
  • Post category:其他




一、移动端屏幕适配概念

在flutter 应用中一般来说我们是没有用单位的,不像传统的开发用了px,rpx,pt,vw等等,但是在实际的开发过程中移动端不同的屏幕我们都需要做适配。在此,就引出三个概念:

逻辑分辨率



物理分辨率



像素比


物理分辨率

:硬件所支持的,即设备分辨率,常常听到的1920,2k屏,物理像素固定,出厂设置好了。


逻辑分辨率(手机屏幕大小)

:软件通过算法达到的,flutter开发中我们用的就是这个逻辑分辨率。


像素比(dpr)

:物理像素与逻辑像素的比例,当像素比为1:1时,使用1个物理像素显示1个逻辑像素;当像素比为2:1时,使用4个物理像素(长2倍,宽2倍,乘起来就是4倍)显示1个逻辑像素




获取设备信息(通过MediaQuery)


  1. 报错分析:首先点击of方法进去


    MediaQueryData必须要初始化好,不然你拿到的就是null


  2. 查看MediaQueryData具体是啥


    初始化MediaQueryData实际上不是用的构造器函数,而是用的MediaQueryData.formWindow方法


  3. 具体看看怎么初始化的





    只有等这个方法初始化完后,才能调用MediaQuery.of(context)

    ,所以要求执行顺序必须是:图五→图一才行,而按照现在的代码顺序却是图一到图五了,所以报错。可以打断点验证整个过程
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
     //一般希望在应用程序启动就拿到手机的物理分辨率
     final physicalWidth=window.physicalSize.width;
     final physicalHeight=window.physicalSize.height;
     print("手机物理分辨率:$physicalWidth*$physicalHeight");

     //在这里通过媒体查询获取手机屏幕宽高(逻辑分辨率)会报错
      // final screenWidth=MediaQuery.of(context).size.width;
     // final screenHeight=MediaQuery.of(context).size.height;
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: "/", 
      routes: {
        "/": (context) => MyHomePage(title: 'Flutter Demo Home Page'), //注册首页路由
      },
    );
  }
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    //放这里不会报错,因为已经初始化完成
     final mediaQueryData=MediaQuery.of(context);
     print(mediaQueryData);
    return new Scaffold(
        appBar: new AppBar(
          title: new Text(widget.title),
        ),
        body: new Center(
          child: new Column(
            children: <Widget>[
              Text('测试'),
              ]
          ),
        ));
  }
}



如果要强行在刚刚报错的地方拿到屏幕宽高怎么办?

回头看源码,发现有这个代码:

size = window.physicalSize / window.devicePixelRatio

那么我们可以在报错的地方直接按照这个写法,跳过初始化的过程(此过程实际上就是用的也是window方法)。



解决方案:
     // 获取dpr
     final dpr=window.devicePixelRatio;
    // 通过仿照源码方式获取手机屏幕宽高(逻辑分辨率)
     final screenWidth= physicalWidth/dpr;
     final screenHeight= physicalHeight/dpr;
      // 同理也可以获取状态栏高度等其它参数
     final statusHeight=window.padding.top/dpr;



二、Flutter屏幕适配可以采用小程序的rpx适配

rpx适配原理:

  • 不管是什么屏幕,统一分成750份
  • 在iPhone5上:1rpx = 320/750 = 0.4266 ≈ 0.42px
  • 在iPhone6上:1rpx = 375/750 = 0.5px
  • 在iPhone6plus上:1rpx = 414/750 = 0.552px

算出一个rpx后,再将自己的size和rpx单位相乘即可: 比如100px的宽度:100 * 2 * rpx 在iPhone5上计算出的结果是84px 在iPhone6上计算出的结果是100px 在iPhone6plus上计算出的结果是110.4px



封装一个适配的工具类

import 'dart:ui';

class ScreenUtil {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static double rpx;

  static void initialize({double standardSize = 750}) {
    // 1.手机的物理分辨率
    physicalWidth = window.physicalSize.width;
    physicalHeight = window.physicalSize.height;

    print("宽高==$physicalWidth --- $physicalHeight");

    // 2.获取dpr
    dpr = window.devicePixelRatio;

    // 3.宽度和高度
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight / dpr;

    // 4.状态栏高度
    statusHeight = window.padding.top / dpr;

    // 5.计算rpx的大小
    rpx = screenWidth / standardSize;
  }

  static px(int size) {
    return rpx *2 * size;
  }
}



工具类的使用

首先需要在入口main.dart初始化

import 'package:flutter/material.dart';
import 'package:flutter_learn/blog/utils/screen_fit.dart';
import 'home/home_page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    ScreenUtil.initialize();
    return MaterialApp(
      title: 'Flutter widget',
      debugShowCheckedModeBanner:false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

然后直接使用工具类

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("首页"),
        ),
        body: Stack(
          children: <Widget>[
            Container(
              width: ScreenUtil.px(200),
              height: ScreenUtil.px(200),
              color: Colors.red,
            ),
            HomePageContent(),
          ],
        ));
  }
}



文末福利

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

在这里插入图片描述

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。



全套视频资料:


一、面试合集

在这里插入图片描述


二、源码解析合集


在这里插入图片描述


三、开源框架合集


在这里插入图片描述


欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓



版权声明:本文为m0_59162559原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。