flutter 螢幕尺寸適配 字型大小適配

__white發表於2018-10-16

前言:

現在的手機品牌和型號越來越多,導致我們平時寫佈局的時候會在個不同的移動裝置上顯示的效果不同,

比如我們的設計稿一個View的大小是300px,如果直接寫300px,可能在當前裝置顯示正常,但到了其他裝置可能就會偏小或者偏大,這就需要我們對螢幕進行適配。

安卓原生的話有自己的適配規則,可以根據不同的尺寸建立不同的資料夾,系統會根據當前的裝置尺寸取對應的大小的佈局。而flutter本身並沒有適配規則,而原生的又比較繁瑣,這就需要我們自己去對螢幕進行適配。

點選直達github地址

如果有幫助,請給我個star
最新程式碼請訪問github

flutter_ScreenUtil

flutter 螢幕適配方案

github: github.com/OpenFlutter…
csdn部落格工具介紹:blog.csdn.net/u011272795/…

使用方法:

安裝依賴:

安裝之前請檢視最新版本

dependencies:
  flutter:
    sdk: flutter
  # 新增依賴
  flutter_screenutil: ^0.4.0
複製程式碼

在每個使用的地方匯入包:

import 'package:flutter_screenutil/flutter_screenutil.dart';

複製程式碼

初始化設定尺寸

在使用之前請設定好設計稿的寬度和高度,傳入設計稿的寬度和高度(單位px) 一定在MaterialApp的home中的頁面設定,以保證在每次使用之前設定好了適配尺寸:

//設定適配尺寸 (填入設計稿中裝置的螢幕尺寸) 假如設計稿是按iPhone6的尺寸設計的(iPhone6 750*1334)
    ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context);
複製程式碼

使用:

適配尺寸:

//傳入設計稿的px尺寸:
適配後的寬度width: ScreenUtil().setWidth(540),
適配後的高度height: ScreenUtil().setHeight(200),
高度也根據setWidth來做適配可以保證不變形

例如:
Container(
           width: ScreenUtil().setWidth(375),
           height: ScreenUtil().setHeight(200),
            ),
複製程式碼

適配字型:

      ScreenUtil().setSp(28)         //傳入字型大小,根據系統的“字型大小”輔助選項來進行縮放
      ScreenUtil().setSp(28,false)  //傳入字型大小,不會根據系統的“字型大小”輔助選項來進行縮放

for example:
        Text(
             'My font size is 28px and will not change with the system.',
                 style: TextStyle(
                   color: Colors.black,
                   fontSize: ScreenUtil().setSp(28, false) 
                 )
             ),

複製程式碼

其他相關api:

    ScreenUtil.pixelRatio       //裝置的畫素密度
    ScreenUtil.screenWidth      //裝置寬度
    ScreenUtil.screenHeight     //裝置高度
    ScreenUtil.bottomBarHeight  //底部安全區距離,適用於全面屏下面有按鍵的
    ScreenUtil.statusBarHeight  //狀態列高度 劉海屏會更高  單位px
    ScreenUtil.textScaleFactory //系統字型縮放比例
    
    ScreenUtil().scaleWidth  // 實際寬度的dp與設計稿px的比例
    ScreenUtil().scaleHeight // 實際高度的dp與設計稿px的比例
    
複製程式碼
//匯入
import 'package:flutter_screenutil/flutter_screenutil.dart';

...

  @override
  Widget build(BuildContext context) {
    //設定適配尺寸 (填入設計稿中裝置的螢幕尺寸) 假如設計稿是按iPhone6的尺寸設計的(iPhone6 750*1334)
    ScreenUtil.instance = ScreenUtil(width: 750, height: 1334)..init(context);
    print('裝置寬度:${ScreenUtil.screenWidth}'); //Device width
    print('裝置高度:${ScreenUtil.screenHeight}'); //Device height
    print('裝置的畫素密度:${ScreenUtil.pixelRatio}'); //Device pixel density
    print(
        '底部安全區距離:${ScreenUtil.bottomBarHeight}'); //Bottom safe zone distance,suitable for buttons with full screen
    print(
        '狀態列高度:${ScreenUtil.statusBarHeight}px'); //Status bar height , Notch will be higher Unit px

    print('實際寬度的dp與設計稿px的比例:${ScreenUtil().scaleWidth}');
    print('實際高度的dp與設計稿px的比例:${ScreenUtil().scaleHeight}');

    print(
        '寬度和字型相對於設計稿放大的比例:${ScreenUtil().scaleWidth * ScreenUtil.pixelRatio}'); 
    print(
        '高度相對於設計稿放大的比例:${ScreenUtil().scaleHeight * ScreenUtil.pixelRatio}'); 
    print('系統的字型縮放比例:${ScreenUtil.textScaleFactory}');

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Row(
              children: <Widget>[
                Container(
                  width: ScreenUtil().setWidth(375),
                  height: ScreenUtil().setHeight(200),
                  color: Colors.red,
                  child: Text(
                    '我的寬度:${ScreenUtil().setWidth(375)}dp',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: ScreenUtil().setSp(12, false),
                    ),
                  ),
                ),
                Container(
                  width: ScreenUtil().setWidth(375),
                  height: ScreenUtil().setHeight(200),
                  color: Colors.blue,
                  child: Text('我的寬度:${ScreenUtil().setWidth(375)}dp',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: ScreenUtil().setSp(12, false),
                      )),
                ),
              ],
            ),
            Text('裝置寬度:${ScreenUtil.screenWidth}px'),
            Text('裝置高度:${ScreenUtil.screenHeight}px'),
            Text('裝置的畫素密度:${ScreenUtil.pixelRatio}'),
            Text('底部安全區距離:${ScreenUtil.bottomBarHeight}px'),
            Text('狀態列高度:${ScreenUtil.statusBarHeight}px'),
            Text(
              '實際高度的dp與設計稿px的比例:${ScreenUtil().scaleHeight}',
              textAlign: TextAlign.center,
            ),
            Text(
              '實際高度的dp與設計稿px的比例:${ScreenUtil().scaleHeight}',
              textAlign: TextAlign.center,
            ),
            Text(
              '寬度和字型相對於設計稿放大的比例:${ScreenUtil().scaleWidth * ScreenUtil.pixelRatio}',
              textAlign: TextAlign.center,
            ),
            Text(
              '高度相對於設計稿放大的比例:${ScreenUtil().scaleHeight * ScreenUtil.pixelRatio}',
              textAlign: TextAlign.center,
            ),
            SizedBox(
              height: ScreenUtil().setHeight(100),
            ),
            Text('系統的字型縮放比例:${ScreenUtil.textScaleFactory}'),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('我的文字大小在設計稿上是14px,不會隨著系統的文字縮放比例變化',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: ScreenUtil().setSp(14, false))),
                Text('我的文字大小在設計稿上是14px,會隨著系統的文字縮放比例變化',
                    style: TextStyle(
                        color: Colors.black, fontSize: ScreenUtil().setSp(14))),
              ],
            )
          ],
        ),
      ),
    );
  }
複製程式碼

使用示例:

example demo

效果:

效果

適配原理

說一下適配方案, 比如我們設計師設計的UI是根據Iphone6來做的,我們知道 iPhone6的解析度是750*1334(px), 又或者是根據hdpi的裝置來設計的UI,我們知道hdpi的 Android裝置是 (240 dpi),畫素密度是1.5,即hdpi裝置的解析度寬度是320px, 總之,無論設計稿的單位是px,或者是dp,我們都能夠轉換成px. 那麼我們如果根據px來適配,ios和 android 就都可以相容了.

假設,我們的設計稿手機是10801920 px. 設計稿上有一個540960 的元件, 即寬度和寬度是手機的一半. 如果我們直接寫的時候元件的尺寸這麼定義,在其他尺寸的裝置上未必是一半,或多,或少. 但是我們可以按比例來看,即我們要實現的寬度是實際裝置的一半. 那麼假設我們裝置的寬度是deviceWidth和deviceHeight , 我們要寫的元件大小為: 寬:(540/1080)*deviceWidth,高度: (960/1920)*deviceHeight.

通過這個公式我們可以發現,我們要寫的元件寬度就是設計稿上的尺寸width*(deviceWdith/原型裝置寬度).那麼每次我們寫ui的時候,只要直接哪來設計稿的尺寸*(deviceWdith/裝置原型)寬度即可.

原理就是先獲取,實際裝置與原型裝置的尺寸比例. 首先flutter獲取裝置的尺寸的程式碼是:

以下資料為我的手機資料:

import 'dart:ui';
//因為window是dart:ui中提供的,所以需要引入這個包.
window.physicalSize  //Size(1080.0, 1794.0)  單位px
width =  window.physicalSize.width  //寬度
height =  window.physicalSize.height  //高度

//使用這個方法則無需引入包
MediaQuery.of(context).size   //Size(411.4, 683.4)   單位:dp
widhtDp = MediaQuery.of(context).size.width   //寬度 411.4
heightDp = MediaQuery.of(context).size.height  //高度 683.4
複製程式碼

設計稿單位是px,且尺寸為1080*1920 px 時:

scaleWidth = width  / 1080;
scaleHeight = height / 1920;
複製程式碼

那麼我們要寫尺寸為500100控制元件的寬度就是 500scaleWidth .100*scaleHeigh ,注意這時單位是px,flutter中預設元件尺寸單位都是dp,我們還要進行px->dp的操作.除以畫素密度就好了. flutter獲取畫素密度的方法:

MediaQuery.of(context).devicePixelRatio
window.physicalSize     
複製程式碼

上面兩種方法得到的是一樣的結果,但是window物件來自dart:ui,所以我們引入這個包:

import 'dart:ui';

設計稿單位是dp,且尺寸為360*640 dp 時:

scaleWidth = widhtDp / 360;
scaleHeight = heightDp / 640;
那麼我們要寫尺寸為500*100控制元件的寬度就是 500*scaleWidth .100*scaleHeigh 
複製程式碼

字型大小適配

setSp(int fontSize, [allowFontScaling = true]) => allowFontScaling
      ? setWidth(fontSize) * _textScaleFactor
      : setWidth(fontSize);
複製程式碼

第一個引數為設計稿中字型的大小,單位px, 第二個引數可選,為控制字型是否要根據系統的“字型大小”輔助選項來進行縮放。預設值為true。

相關文章