🀄

FlutterでSafeAreaじゃないとこの高さを取得して色々使う

2020/12/23に公開
class SafeAreaUtil {
  factory SafeAreaUtil() => _cache;
  SafeAreaUtil._internal();
  static final SafeAreaUtil _cache = SafeAreaUtil._internal();

  static double unSafeAreaBottomHeight;
  bool get hasUnSafeAreaBottomHeight => unSafeAreaBottomHeight != 0.0;
}

シングルトン的な何かを作る。

class App extends StatelessWidget {
  const App();

  
  Widget build(BuildContext context) => MaterialApp(
        title: 'title',
        home: Home(),
        builder: _builder,
        ...(themeとか色々),
      );

  Widget _builder(BuildContext context, Widget child) {
    SafeAreaUtil.unSafeAreaBottomHeight = MediaQuery.of(context).padding.bottom;
    return child;
  }
}

アプリ起動時に計算して挿入。
(shared preferenceに入れても良さそうだけど、OSのアップデートとかでSafe Areaの仕組み変わるとかあると怖い。)

class SimpleFooter extends StatelessWidget {
  const SimpleFooter({ this.child});

  final Widget child;

  
  Widget build(BuildContext context) => Container(
        color: Theme.of(context).footerColor,
        height: _height(context),
        child: _column(context),
      );

  double _height(BuildContext context) => simpleFooterHeight(
        hasSafeAreaHeight: _hasSafeArea,
      );

  double simpleFooterHeight({ bool hasSafeAreaHeight}) =>
    hasSafeAreaHeight ? 83 : 72;

  bool get _hasSafeArea =>
      SafeAreaUtil().hasUnSafeAreaBottomHeight;

  Column _column(BuildContext context) => Column(
        children: <Widget>[
          _divider(context),
          _padding,
          if (_hasSafeArea) const SizedBox(height: 11),
        ],
      );

  Divider _divider(BuildContext context) => Divider(
        height: 0.5,
        color: Theme.of(context).borderColor,
      );

  Padding get _padding => Padding(
        padding:
            const EdgeInsets.only(left: 12, top: 11.5, right: 12, bottom: 12),
        child: child,
      );
}

こんな感じで呼び出します。

基本はSafeArea Widgetを使うのが正解だと思いますが、
小回り利かせたい時には参考にして頂けると👍

Discussion