Flutter備忘録: AnimatedSwitcherとフルスクリーン表示 (BoxFit)

AnimatedSwitcherウイジェットを使って、2つのウイジェットの表示をアニメーション効果付きで切り替える際、前後で表示されるウイジェットにBoxFitプロパティで全画面に拡大表示しているウイジェットがあると実際の表示が全画面にならない場合があったのでその解決法をメモしておきます。


キ-ワード: #AnimatedSwitcher #全画面表示 #layoutBuilder #カスタムLayoutBuilder

現在、開発環境をFlutterに移行中のスマホアプリ『コメ欄』に、設定した複数の画像から1つをアプリの背景画像として表示させる画面があります。 画像の表示にはImageウイジェットを使っていますが、表示する画像の画素サイズが、スマホ画面の大きさとは違う場合がほとんどなので、ImageウイジェットのfitプロパティにBoxFitを指定して背景に設定する画像を画面の大きさに合わせて拡大、縮小や、引き延ばしをして表示出来る様にしています。

例:『コメ欄』の画面 (1080x2220)

画素が610x800 (①)と 808x808 (②)の画像が画面上に拡大表示されています (BoxFit.cover)
『コメ欄』背景画像表示例 ①
背景画像表示例 ①
『コメ欄』背景画像表示例 ②
背景画像表示例 ②

背景画像表示例として「いらすとや」のサンプル素材を背景画像として使わせてもらいました。


AnimatedSwitcherウイジェット

背景画像は複数設定可能なため、アプリ内で切り替える事が出来ますが、その際に瞬時に画像が切り替わるのではなく、フェードアウト・フェードインを組み合わせたクロスフェードのアニメーションで切り替えたかったのでAnimatedSwitcherウイジェットを使ってクロスフェードのアニメーションを実装してみました。

しかし。。。

AnimatedSwitcherウイジェット使用例 ①
AnimatedSwitcher使用例 ①
AnimatedSwitcherウイジェット使用例 ②
AnimatedSwitcher使用例 ②

画像の切り替えはクロスフェードのアニメーション付きで表示される様になりましたが、残念ながら、AnimatedSwitcherウイジェットのリファレンスページのコード例にあった方法をそのまま使っただけだと、うまく全画面表示になりませんでした。。。


AnimatedSwitcher.defaultLayoutBuilder

AnimatedSwitcherウイジェットには「layoutBuilder」というプロパティがありますが、このプロパティを設定しない場合は規定値として「AnimatedSwitcher.defaultLayoutBuilder」が選択されます。

このdefaultLayoutBuilderのリファレンスページによると、コード内にStackウイジェットが使われていると説明がありましたが、同じページにImplementaion (実装ソース)があったので見たところ、次の様になっていました:

static Widget defaultLayoutBuilder(Widget? currentChild, List<Widget> previousChildren) {
  return Stack(
    alignment: Alignment.center,
    children: <Widget>[
      ...previousChildren,
      if (currentChild != null) currentChild,
    ],
  );
}

Stackウイジェットの表示サイズは、規定値だと、childrenプロパティで指定される子ウイジェットのリストで一番表示サイズが大きいウイジェットの大きさに設定される仕様になっています。

でも、この子ウイジェットの大きさを比較する時点では、まだStackウイジェットの親ウイジェットの大きさは考慮されない為、子ウイジェットにBoxFitが設定されていても、Stackウイジェットの大きさにBoxFitする解釈になってしまうみたいです。


上の例では、画面の大きさが1080x2220で、例①で背景画像に使った画像の画素は610x800、例②の場合は808x808ですが、AnimatedSwitcherウイジェットのlayoutBuilderプロパティが設定されていない場合は、AnimatedSwitcherウイジェットの大きさが①と②で表示される画像の大きい方の画像の大きさ、808x808に調節されてしまっているみたいです。

そして結果として、808x808よりも幅が狭い①の画像の場合、BoxFit.coverが設定されている為、808x808の大きさを全て覆う大きさに拡大されて表示された様です。


Stackウイジェットを親ウイジェットの大きさに合わせる

Stackウイジェットを親ウイジェットの大きさに合わせるのには、StackウイジェットのfitプロパティにStackFit.expandを指定すれば良いのですが。。そうなると次の様にAnimatedSwitcher.defaultLayoutBuilderに「fit: StackFit.expand,」をつけ加えたLayoutBuilderを新たに宣言して:

Widget fullScreenLayoutBuilder (Widget? currentChild, List<Widget> previousChildren) {
  return Stack(
    fit: StackFit.expand,
    alignment: Alignment.center,
    children: <Widget>[
      ...previousChildren,
      if (null != currentChild) currentChild,
    ],
  );
}

StackウイジェットのlayoutBuilderプロパティに指定する必要がありました。

AnimatedSwitcher(
  duration: const Duration(milliseconds: 800),
  layoutBuilder: fullScreenLayoutBuilder,
  child: InAppConfigWidget(
    key: ValueKey<int>(config.index),
    … などなど(一部省略) …
  ),
)

結果

以上の設定で次の動画の例にある様に、無事、全画面表示のクロスフェードのアニメーションが有効になりました。



コメント

このブログの人気の投稿

[OBS] Twitchコメント欄向けCSSカスタマイザー (試作)

『コメ欄』用カスタムCSS - L◯NE風 (ツイキャス) - OBSのブラウザでも使えます。

[ツイキャス配信・閲覧支援ツール] キャスポケットツール: 初期設定

ツイキャスで他の人がサポートしている人って見えますか? (キャスポケットツール)

[OBS] コメントを逆の順番で表示 (ツイキャス/YouTube)

ツイキャス専門 『コメ欄』Lite (ライト)と『コメ欄』✚ (プラス)

キャスポケットツール: 検索の巻 (ツイキャスのユーザー検索とライブ検索)

最近のプロジェクト (Pololu社 SMC: DCモーター制御ボード)