FlutterでAppBarをタップしてスクロールリセットする

「来期アニメ」アプリで、AppBarをタップしたらスクロールを一番上に戻す処理を入れたかったので調べました。

AppBar自体にはonTapイベントはないようで、stack over flowにちょうど良いのがあったので参考にさせてもらいました。

Add onTap listener to appBar (Flutter)
We need to add onTap listener to appBar. Not an actions or leading button. We need it for all appBar. I tried to use InkWell, but it has visual effect, we no n...

結果はこんな感じです。

StatelessWidgetを継承したWidgetを作って、AppBarをGestureDetectorで囲み、onTapイベントをつけるような感じです。

// custom_app_bar.dart

import 'package:flutter/material.dart';

// PreferredSizeWidget:最適なサイズに変更するウィジェット
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  final VoidCallback onTap;
  final AppBar appBar;

  const CustomAppBar({
    Key? key,
    required this.onTap,
    required this.appBar,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(onTap: onTap, child: appBar);
  }

  //preferredSize:制約がないときに設定するデフォルトサイズ
  // kToolbarHeight:appBarの高さの定数
  // Size.fromHeight:指定された高さでsizeを作成
  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

使い方はこんな感じです。

 Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(
        onTap: () {
          // AppBarがタップされたときの処理
        },
        appBar: AppBar(
          title: Text(widget.title),
        ),
      ),
      body: 

次はスクロール。
ListViewはインデックスや座標指定のスクロールに対応していないそうなので、調べて「scrollable_positioned_list」を使うことにしました。
インデックス指定でスクロールできるパッケージです。

0.1.10はnull-safety対応されてないらしくエラーになってしまったので、次のリリースの0.2.0-nullsafety.0を使いました。

scrollable_positioned_list: ^0.2.0-nullsafety.0

AppBarをタップしたときに一瞬でスクロールリセット、↑ボタンを押したときにスクロールしながら一番上まで戻るようにしてみました。

class _MyHomePageState extends State<MyHomePage> {
  final ItemScrollController _itemScrollController = ItemScrollController();
  final ItemPositionsListener _itemPositionsListener =
      ItemPositionsListener.create();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(
        onTap: () {
          _itemScrollController.jumpTo(index: 0); // 一瞬でスクロールリセット
        },
        appBar: AppBar(
          title: Text(widget.title),
        ),
      ),
      body: ScrollablePositionedList.builder(
        itemCount: List.generate(1000, (i) => i).length,
        itemBuilder: (context, index) =>
            Text(index.toString(), style: TextStyle(fontSize: 24)),
        itemScrollController: _itemScrollController,
        itemPositionsListener: _itemPositionsListener,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // スクロールしながら一番上まで1秒で戻る。
          _itemScrollController.scrollTo(
              index: 0,
              duration: Duration(milliseconds: 1000),
              curve: Curves.easeInOutCubic);
        },
        child: Icon(Icons.arrow_upward),
      ),
    );
  }
}

以上、FlutterでAppBarをタップしてスクロールリセットする方法を紹介しました。

この機能を実装予定の「来期アニメ」を始めとする拙作アプリをぜひお試しください。

コメント

タイトルとURLをコピーしました