anz blog

リストをバウンスしてる時の背景色を指定したい

2020-02-06 #Flutter

2020年一発目の記事は Flutter スタートです!
(その前にBitriseからプレゼントもらったやつ書いてたけど...)

やりたいこと

Flutter で ListView を使うと簡単にリスト表示ができて便利なのですが、
iOS で動かしたときに少し気になることがあります。(Flutterに限った話ではないですが(笑))

リストの1つ目のものをヘッダーという扱いにして、NavigationBar などと同色にした時に、
iOS の場合はリストがバウンスするのでヘッダー部分と NavitaionBar の間に隙間ができて少し気になります。
それをどうにかしたいという話です。

間に見える白が嫌だ!

やったこと

まず思いついたのが、ListView は背景色が特に指定されていないので、Container などで背景色を指定してあげて、
各アイテムでは白色を指定すると一応それっぽくはなるのですが、
このやり方だといくつかのケースで不満がのこります。

  • ListView の下部までもその影響を受ける
    • アイテムが少ない場合(画面を越えない場合)はなかなかにきつい結果になる
  • 各アイテムで白で背景色を指定するのがだるい。Divider とかつかいだすともう。。

というのがあって、他の方法を探すことにしました。

(バウンスさせないようにするっていう解決策がこれでいいなら最も楽で簡単です(笑))

できた方法

そこで、バウンスエリアに該当するところに背景色を指定するためだけに専用の Widget を追加してそれでやろうという方法です。
この方法でやるとして越える障害(笑)は、バウンスの状況(スクロール位置)を監視しながらそれを埋めるように Widget を伸縮させるということです。
伸縮させることなくある程度の高さをもたせた Widget を用意しておけばよさそうだけれども、
もし表示するアイテムが少ない2つとか3つの場合だとそれが見えてしまうという可能性があるのが...

ざっくり考えた方法は

  • NavigationBar と ListView の間に Container を挿入する
  • ScrollController を使ってスクロールを監視する
  • ChangeNotifie をつかって必要に応じて伝播させる
  • 差し込んだ ContainerChangeNotifier から伝わってきた値をつかって伸縮させる

みたいな感じで実装してみたら、一応できました。

そうそうこんな感じ!

コード

コード全部を一応貼っておきます。

Android だと要らない処理なので、ざっくりきりわけるとしたら

@override
void initState() {
  super.initState();
  
  if (Platform.isIOS) {
    _controller.addListener(_scrollControllerListener);
  }
}

として、iOSのときだけ追加したらスクロールを監視することはなくなるので、
影響を最小限に抑えられそうですか。。ね?

しかし...もっとスマートにできる気がして気が気じゃない(笑)