📝

【 Flutter】SafeAreaの使い方って二種類あるよねって話

に公開

SafeAreaの使い方について

端末の凹みやノッチなどでUIが見えないことをを避けるためにSafeAreaを使うことは多いと思います。ただそのやり方は二種類あるかなと思ったので記事にさせて頂きます。

①画面の上部下部には何も表示しない方法
この方法だととても楽に実装できます。

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: List.generate(
              100,
              (index) => index,
            ).map((e) => Center(child: Text('index id $e'))).toList(),
          ),
        ),
      ),
    );
  }

②画面の上部下部は避けつつも目一杯表示する方法
SafeAreaではなくMediaQuery.paddingOfは使用していますが、この方法だと画面いっぱいを使って表示することができます。

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            SizedBox(height: MediaQuery.paddingOf(context).top),
            ...List.generate(
              100,
              (index) => index,
            ).map((e) => Center(child: Text('index id $e'))).toList(),
            SizedBox(height: MediaQuery.paddingOf(context).bottom),
          ],
        ),
      ),
    );
  }

また、ListViewを使用すると特に意識することなくこのやり方でやってくれます。

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: List.generate(
          100,
          (index) => index,
        ).map((e) => Center(child: Text('index id $e'))).toList(),
      ),
    );
  }

SafeAreaやListViewを使わない場合の注意点

SafeAreaはただpaddingを与えているだけでなく、MediaQuery.removePaddingをしてくれており子孫WidegetのMediaQuery.paddingOfの値をremoveしてくれます。

  
  Widget build(BuildContext context) {
    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,
      ),
    );
  }

それにより不要に上下のpaddingを意識することを防いでくれます。

      Builder(builder: (context) {
       print(MediaQuery.paddingOf(context).top); // 59.0
       return SafeArea(
         child: Builder(builder: (context) {
           print(MediaQuery.paddingOf(context).top); // 0.0
   Builder(builder: (context) {
       print(MediaQuery.paddingOf(context).top); // 59.0
       return ListView(
         children: [
           Builder(
             builder: (context) {
               print(MediaQuery.paddingOf(context).top); // 0.0

Discussion