TabBarの選択ボタンを中央寄せにするアニメーション付き無限スクロール化するTips2

エキサイト株式会社の高野です。
前回 TabBarの選択ボタンを中央寄せにするアニメーション付き無限スクロール化するTips を書いたのですが、また別の方法で実装しましたのでその方法を紹介します。
(前回と同様にTabBarをListViewで実装する際の一例です。)

各バージョン

Flutter: 2.0.6
iOS: 14.5
Android: 11.0

使用ライブラリ

scrollable_positioned_list

前回の実装

前回の実装ではAndroidの各種端末とiPhoneの指定すべきinitialOffsetが違うのでListViewが生成途中に中央に寄せるメソッドが発火していたので以下のようになっていました。
f:id:exRyusei1026:20210617163231g:plain

修正後実装方法

まず以下のようにControllerのインスタンスを生成します。今回はListenerを使用していないので必要な場合は同様に生成してください

// Controllerの生成
final ItemScrollController itemScrollController = ItemScrollController();
// Listenerの生成
final ItemPositionsListener itemPositionsListener = ItemPositionsListener.create();

そうしましたら、以下のようにbuilderを用いてTabの生成を記述します。

ScrollablePositionedList.builder(
     itemScrollController: scrollController,
     initialScrollIndex: (allTabQuantity / 2) + (allTabQuantity % 2),
     initialAlignment: alignment,
     scrollDirection: Axis.horizontal,
     itemCount: allTabQuantity,
     itemBuilder: (_, index) {
         return Button();
     },
),

initialScrollIndex で中央の要素を指定し、initialAlignment で指定した要素の位置を指定することができます。
alignmentで指定する際にコメントで

  /// * 0 aligns the left edge of the item with the left edge of the view
  /// * 1 aligns the left edge of the item with the right edge of the view.
  /// * 0.5 aligns the left edge of the item with the center of the view.

このように書かれています。0.5を指定すると要素の左端が中央に揃えられるとのことですが、自分の期待しているのは要素の中央を画面の中央に揃えて欲しいのです。
なのでalignmentを中央に来るように指定しなければなりません。
そのために MediaQuery.of(context).size.width とボタンサイズを用いて画面のWidthに対するボタンの半分のWidthの割合を導出していきます。式としては、

halfButtonRatio = ButtonWidth / 2 / MediaQuery.of(context).size.width;

以上のようになります。
この halfButtonRatio を0.5から引くことによってボタンの中央が画面の中央に来るalignmentを導出することができました。
また、タップイベントは

itemScrollController.scrollTo(
  index: index,
  duration: duration,
  alignment: 0.5 - halfButtonRatio,
);

以上でタップの際に中央にアニメーションをすることができます。
f:id:exRyusei1026:20210617163320g:plain

まとめ

一部の例としてTabBarを無限スクロールにする方法でした。
ライブラリで良さそうなものや別の実装方法がありましたらコメントしていただけると幸いです。

現在、エキサイト株式会社では採用に絶賛力を入れています。
インターンでは以下のものが公開されています。
▼入門コース
https://www.wantedly.com/projects/630117
▼実戦コース
https://www.wantedly.com/projects/644989

よければお気軽にご応募ください。