♾️

InteractiveViewerで無限スクロールする

2024/12/09に公開

InteractiveViewerは、ビューポート(InteractiveViewerの表示領域)のサイズを超える子ウィジェットをスクロール操作できるウィジェットです。ドラッグとズームも可能で便利なウィジェットですが、ビューポートをスクロール可能な範囲の扱いがわかりにくいかもしれません。

デフォルトの挙動

デフォルトの挙動では、ビューポートのスクロール範囲は子ウィジェットの範囲内になります。子ウィジェットの範囲外の余白は表示されず(縮小時を除く)、範囲外にスクロールもできません。画像ビューアーや地図をイメージするとわかりやすいでしょう。

デフォルトのスクロール範囲:

コード:

InteractiveViewer(
  // constrainedをfalseにすると、子ウィジェットのサイズが
  // ビューポートの範囲を超える場合にスクロール可能になります
  constrained: false,
  child: Image.asset('images/earth.jpg'),
),

boundaryMargin

余白の幅は、コンストラクタのパラメーター boundaryMargin で指定できます。デフォルト値は0で、余白は表示されません。

常に余白を用意したい場合は 0 より大きな値を指定します。余白を埋めるウィジェットの指定方法は用意されていないので、Stackなり何なりで背景を用意するといいでしょう。

boundaryMargin が 100 の挙動:

コード:

InteractiveViewer(
  constrained: false,
  boundaryMargin: EdgeInsets.all(100),
  child: Image.asset('images/earth.jpg'),
),

無限スクロール

boundaryMarginにinfinityを指定すると余白が無限に生成されるようになり、無限スクロールが可能になります。これに気づくまでずいぶん遠回りしました…

無限スクロールの挙動:

コード:

InteractiveViewer(
  constrained: false,
  // 余白を無限にする
  boundaryMargin: EdgeInsets.all(double.infinity),
  child: Image.asset('images/earth.jpg'),
),

注意点として、InteractiveViewer用のスクロールバーのウィジェットは用意されていません。パンやズームに対応するスクロールバーをつけたい場合はScrollbarとの連携を自前で実装する必要があります。ScrollViewと異なり、ScrollbarはInteractiveViewerを囲んでも動作しないので注意してください。

InteractiveViewerを拡張、あるいはラップするパッケージはいくつかあるのですが、決定的なものはないように思えます。InteractiveViewerができることは多く、ユーザーによって要件も様々なので、多くのユーザーが納得する上位互換のウィジェットを作るのは難しそうです。

Discussion