Flutter全面屏適配


筆者在這篇文章ReactNative全面屏(Android)適配問題提及了現在的全面屏問題,不僅是Android平台,IOS平台也是,給我的感覺就是手機越來越長了。
現在的手機長寬比早就不是之前的16:9了,比如iphoneX 的長寬比為13:6,而現在多數的Android手機都到了19.5:9,有的甚至達到了21:9。
基於科技的發展(適配的血淚史),Flutter開發自然也需要注意這個問題。
在Flutter開發中,通常使用Scaffold的appBar和bottomNavigationBar組件的頁面是沒有適配問題,它內部對全面屏進行了適配。
適配問題主要是出現在沒有使用Scaffold的情況下。
看一下這段代碼,沒有使用Scaffold:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(    
        primarySwatch: Colors.blue,
      ),
    home: Container(
      color: Colors.white,
    child: Column(
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        Container(
          color: Colors.lightBlue,
          child: Text('頭部'),
        ),
        Container(
          color: Colors.redAccent,
          child: Text('底部'),
        )
      ],
    ),
    )
    );
  }
}

運行效果如下:
在這里插入圖片描述

可以看到上面和下面的組件已經被遮擋了,這就出現了適配問題,適配的主要問題就是集中在如下兩點:

  1. 頂部的NavigationBar預留安全區域
  2. 底部的NavigationBar預留安全區域

對於以上兩種問題,Flutter給出了除上面使用Scaffold,還有如下兩種方案:

  1. 使用Flutter框架提供的SafeArea,Widget進行包裹組件來適配全面屏,這個組件和ReactNative框架中的SafeAreaView這個組件差不多效果,從兩個名字就可以看出來,😀。
  2. 可以通過Flutter系統提供的MediaQuery.of(context).padding 這個Api來獲取上下左右的安全padding,根據這個padding進行適配,更加靈活性。

接下來具體看一下這兩個方案的使用

使用SafeArea適配

這個使用比較簡單,只要需要將組件進行包裹即可,

home: SafeArea(child: Container(
      color: Colors.white,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(
            color: Colors.lightBlue,
            child: Text('頭部'),
          ),
          Container(
            color: Colors.redAccent,
            child: Text('底部'),
          )
        ],
      ),
    ))

使用MediaQuery.of(context).padding適配

home位置修改為如下代碼:
home: SafePage()
-------------------
創建一個SafePage
class SafePage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    EdgeInsets paddings = MediaQuery.of(context).padding;
    return Container(
        color: Colors.white,
        padding: EdgeInsets.fromLTRB(0, paddings.top, 0, paddings.bottom),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Container(
              color: Colors.lightBlue,
              child: Text('頭部'),
            ),
            Container(
              color: Colors.redAccent,
              child: Text('底部'),
            )
          ],
        ),
    );
  }
}

以上兩種方案運行效果如下圖,可以看到頭部和底部已經正常顯示了。
在這里插入圖片描述

上面這兩種方案適用於IOS和Android兩個平台,對於Android平台的適配在ReactNative全面屏(Android)適配問題也提到了另外的一種方案,看大家的實際需要,來采取合適的適配方案。

查看一下SafeArea這個Widget組件的源碼,可以看到其實內部也是采用了上面提到的第二種方案,相當於SafeArea對第二種方案的封裝,開發中使用起來更方便一下,源碼如下

@override
  Widget build(BuildContext context) {
    assert(debugCheckHasMediaQuery(context));
    /// 如下五行代碼就是SafeArea可以進行適配的原因,
    final MediaQueryData data = MediaQuery.of(context);
    EdgeInsets padding = data.padding;
    // Bottom padding has been consumed - i.e. by the keyboard
    if (data.padding.bottom == 0.0 && data.viewInsets.bottom != 0.0 && maintainBottomViewPadding)
      padding = padding.copyWith(bottom: data.viewPadding.bottom);

    return Padding(
      padding: EdgeInsets.only(
        left: math.max(left ? padding.left : 0.0, minimum.left),
        top: math.max(top ? padding.top : 0.0, minimum.top),
        right: math.max(right ? padding.right : 0.0, minimum.right),
        bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
      ),
      child: MediaQuery.removePadding(
        context: context,
        removeLeft: left,
        removeTop: top,
        removeRight: right,
        removeBottom: bottom,
        child: child,
      ),
    );
  }

截圖可能看起來更方便,注意看紅框部分
在這里插入圖片描述

關於Flutter的全面屏適配先分享這些。

歡迎關注我的公眾號:君偉說。分享移動開發技術,職場生活和工作中的酸甜苦辣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM