首頁 > 軟體

Flutter應用框架搭建之螢幕適配詳解

2022-03-19 19:00:37

因移動裝置的多樣性,特別是 Android 的碎片化嚴重,存在各種各樣的解析度,而 Flutter 跨平臺開發又需同時支援 Android 和 iOS ,為儘可能的還原設計圖效果提升使用者體驗,螢幕適配就勢在必行了。

Flutter 暫時沒有官方的螢幕適配方案,在 Flutter 專案開發中目前大部分的適配方案都是通過比例來進行適配,是一個通用的適配方法,該適配方法也在前端、Android、iOS、小程式等開發中廣泛使用。

原理

UI 設計的時候一般會按照一個固定的尺寸進行設計,如 360 x 690 ,實際裝置解析度可能是 Google Pixel: 1080 x 1920 、Google Pixel XL: 1440 x 2560 、iPhone 12 Pro Max: 1284 x 2778 等等。開發時如果直接按照設計圖寫死數值則會出現最後實現的效果跟設計效果不一致的情況。這個時候就可以用比例的方式來進行適配。

將設計圖分為固定單位並給這個單位定義一個標識,例如就叫 w,然後通過獲取裝置解析度,使用裝置真實寬度除以設計圖寬度 ,就得到了 1w 代表的真實寬度:

1w = 裝置真實寬度 / 設計圖寬度

如設計圖尺寸是 360 x 690 ,則寬度為 360w ,真實裝置寬度為 1080 則 1w = 1080 / 360 = 3

根據上面的演演算法,得到對應裝置的 1w 的真實寬度:

Google Pixel: 1w = 1080 / 360 = 3

Google Pixel XL: 1w = 1440 / 360 = 4

iPhone 12 Pro Max: 1w = 1284 / 360 = 3.57

按照同樣的演演算法,可以給高度定義一個單位為 h , 得出對應裝置的高度單位的真實值,如下:

Google Pixel: 1h = 1920 / 690 = 2.78

Google Pixel XL: 1h = 2560 / 690 = 3.71

iPhone 12 Pro Max: 1h = 2778 / 690 = 4.03

得到換算以後 wh 的真實值以後,開發過程中就可以使用其來設定 UI 控制元件的高、寬、間距等,使其最終呈現的效果無限接近設計圖的效果。

開發過程中一般採用寬度來進行適配,控制元件高度要麼自適應,要麼也設定寬度的單位,然後整體高度根據內容自適應。但是如果有特殊需求也可以使用高度來進行適配,比如需求要求是 banner 佔螢幕的 1/4 ,或者要求內容剛好一屏顯示,這個時候設定控制元件的高度時就可以採用高度單位來進行適配。

基於上面的演演算法,在專案中就可以實現對應的適配方案了,但本著不重複造輪子的思想,專案開發中可以直接使用 flutter_screenutil 這個適配庫。

flutter_screenutil

flutter_screenutil 就是基於上述比例適配原理而實現的螢幕適配庫。 目前最新版本是 5.0.1,在 GitHub 上擁有 2.8k 的 star 。在 pub.dev 上擁有1536 個 like ,130 的 pub 指數, 99% 的人氣,說明這是一個靠譜的輪子。

flutter_screenutil:讓你的UI在不同尺寸的螢幕上都能顯示合理的佈局!

新增依賴

在專案根目錄的 pubspec.yaml 中新增 flutter_screenutil 的依賴:

dependencies:
  flutter:
    sdk: flutter
  # 新增依賴
  flutter_screenutil: ^5.0.1

初始化

flutter_screenutil 提供了兩種方式進行初始化:ScreenUtilInit 方式和 ScreenUtil.init 方式。首先在使用的地方匯入包:

import 'package:flutter_screenutil/flutter_screenutil.dart';

ScreenUtilInit

使用 ScreenUtilInit 方式進行初始化,需要將專案的 MaterialApp 進行一層包裹,然後在 builder 中返回專案本身的 MaterialApp ,在 ScreenUtilInit 的 designSize 引數中傳入設計圖的尺寸,實現如下:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: Size(360, 690), //傳入設計圖尺寸
      builder: () => MaterialApp(
        ...
      ),
    );
  }
}

ScreenUtil.init

直接使用 ScreenUtil.init 方法,傳入螢幕尺寸、設計圖尺寸和螢幕方向即可對 flutter_screenutil 進行初始化,程式碼如下:

ScreenUtil.init(
  BoxConstraints(
    maxWidth: MediaQuery.of(context).size.width,  //螢幕寬度
    maxHeight: MediaQuery.of(context).size.height, //螢幕高度
  ),
  designSize: const Size(360, 690), // 設計圖尺寸
  orientation: Orientation.portrait); // 螢幕方向

使用這種方式只需在使用 flutter_screenutil 前進行初始化即可,一般放在根路由即第一個頁面載入的時候進行初始化。

注意:ScreenUtil.init 不能在 MyApp 中進行初始化,會報如下錯誤 No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of(). This can happen because you have not added a WidgetsApp, CupertinoApp, or MaterialApp widget (those widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above those widgets. 因為這個時候還沒載入 MaterialApp 無法使用 MediaQuery.of(context ) 獲取到螢幕寬高

關於上面兩種初始化方法,flutter_screenutil 作者推薦使用第二種方式。

使用

初始化以後就可以使用 flutter_screenutil 提供的方法獲取到適配後的數值進行使用了。

可通過如下 api 獲取寬高以及字型的適配數值:

ScreenUtil().setWidth(540)  //根據螢幕寬度適配尺寸
ScreenUtil().setHeight(200) //根據螢幕高度適配尺寸(一般根據寬度適配即可)
ScreenUtil().radius(200)    //根據寬度或高度中的較小者進行調整
ScreenUtil().setSp(24)      //字型大小適配

傳入的引數即為設計圖上的大小。在實際使用中的範例如下:

Container(
  width: ScreenUtil().setWidth(200),
  height: ScreenUtil().setHeight(540),
  child: Text("Hello", style: TextStyle(fontSize: ScreenUtil().setSp(24)),),
);

這樣即可使用適配的數值進行開發。

但發現這樣寫太麻煩了,為了獲取一個適配的數值,要寫一串的很長的程式碼。flutter_screenutil 提供了更簡潔的呼叫方法,使用 Dart 擴充套件為 num 型別擴充套件了一系列屬性可以方便開發者呼叫,上面的 api 可以通過擴充套件屬性進行如下轉換:

ScreenUtil().setWidth(540)  =>  540.h
ScreenUtil().setHeight(200) =>  200.w
ScreenUtil().radius(200)    =>  200.r
ScreenUtil().setSp(24)      =>  24.sp

修改後的使用範例如下:

Container(
  width: 200.w,
  height: 540.h,
  child: Text("Hello", style: TextStyle(fontSize: 24.sp),),
);

這樣就簡潔多了。

注意:根據前面講解的適配原理知道,一般情況下 1.w != 1.h ,除非剛好螢幕解析度比例與設計圖比例一致,所以如果要設定正方形,切記使用相同的單位,如都設定相同的 w 或者 h ,否則可能顯示為長方形。

除了上面 4 種擴充套件屬性以外,還提供了 sm 以及 swsh

  • sm :取數值本身與 sp 的值最小的值,如 12.sm 則取 1212.sp 的值進行比較,取最小的值。
  • sw :screen width 的縮寫,即螢幕寬度,作用是按螢幕寬度比例返回值。如 0.2.sw 則返回螢幕寬度的 20%,1.sw 則是整個螢幕寬度
  • sh :screen height 的縮寫,及螢幕高度,作用與 sw 類似,返回指定比例的螢幕高度值。如 1.sh 為整個螢幕高度

使用 sp 作為字型單位,預設是會隨著系統字型縮放進行變化,如果不想字型隨著系統縮放而變化,可設定 textScaleFactor1.0 來實現。專案中可對 MaterialApp 進行全域性設定或者對 Text 進行單獨設定:

全域性設定:

MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter_ScreenUtil',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        builder: (context, widget) {
          return MediaQuery(
            ///設定文字大小不隨系統設定改變
            data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
            child: widget,
          );
        },
        home: HomePage(title: 'FlutterScreenUtil Demo'),
      ),

Text 單獨設定:

Text("text", textScaleFactor: 1.0)

效果

附上官方效果圖:

其他 Api

除了適配的 api 以外,flutter_screenutil 還提供了很多實用的 api ,如下 :

  • ScreenUtil().pixelRatio :裝置的畫素密度
  • ScreenUtil().screenWidth :螢幕寬度,等同於 1.sw
  • ScreenUtil().screenHeight :螢幕高度,等同於 1.sh
  • ScreenUtil().bottomBarHeight :底部導航高度,如全螢幕底部按鍵的高度
  • ScreenUtil().statusBarHeight :狀態列高度
  • ScreenUtil().textScaleFactor :系統字型縮放比例
  • ScreenUtil().scaleWidth :實際寬度與設計圖寬度的比例
  • ScreenUtil().scaleHeight :實際高度與設計圖高度的比例
  • ScreenUtil().orientation :螢幕方向

到此這篇關於Flutter應用框架搭建之螢幕適配詳解的文章就介紹到這了,更多相關Flutter螢幕適配內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com