🔄

FlutterのPull To Refreshで下から上に引っ張って更新できるようにする方法

2023/06/29に公開

FlutterのPull To Refreshは、通常は画面を「上から下に」引っ張ることで更新できます。

ListViewで要素を通常通り上から並べる場合はこれで問題ないのですが、
ListViewを上下逆順にし、要素を下から上に並べたときは、Pull To Refreshも「下から上に」引っ張って更新できるようにしたいので、(やや強引な)方法を考えました。
より良い方法がありましたら教えてください。

Pull To Refreshで下から上に引っ張って更新できるようにする方法

RefreshIndicatorウィジェットをTransform.rotateで半回転させ、
さらにListViewの要素一つ一つもTransform.rotateで半回転させます。

Transform.rotate(
  angle: pi,
  child: RefreshIndicator(
    onRefresh: () async {
      // ここにRefreshしたときの更新処理を入れる
    },
    child: ListView.builder(
      itemCount: _list.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Transform.rotate(
            angle: pi,
            child: Center(
              child: Text(_list[index]),
            ),
          ),
        );
      },
    ),
  ),
),

仕組みとしては、
RefreshIndicatorを上下逆にすることで、下から上にPull To Refreshできるようになります。
ただこのままではListView自体も上下逆になってしまうので、要素一つ一つを上下逆にすることで、要素が正しい向きで、ListViewの下から上に向かって並びます。

Transform.rotateの回転させる角度はangle: pi(ラジアン表記)で180度が指定できます。
import 'dart:math';が必要です)

これで、ListViewの要素を下から上に並べた状態で、下からスワイプしてリフレッシュインジケーターが出るようになりました。

全体のコード

import 'dart:math';
import 'package:flutter/material.dart';

class ReversePullToRefreshPage extends StatefulWidget {
  const ReversePullToRefreshPage({super.key});

  
  State<ReversePullToRefreshPage> createState() =>
      _ReversePullToRefreshPageState();
}

class _ReversePullToRefreshPageState extends State<ReversePullToRefreshPage> {
  List<String> _list = ['A', 'B', 'C', 'D'];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pull To Refresh'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Transform.rotate(
        angle: pi,
        child: RefreshIndicator(
          onRefresh: () async {
            // ここにRefreshしたときの更新処理を入れる
          },
          child: ListView.builder(
            itemCount: _list.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Transform.rotate(
                  angle: pi,
                  child: Center(
                    child: Text(_list[index]),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

おまけ:変更前の全体のコード

普通に要素を上から並べるListViewで、上から下にPull To Refreshするコード

import 'dart:math';
import 'package:flutter/material.dart';

class PullToRefreshPage extends StatefulWidget {
  const PullToRefreshPage({super.key});

  
  State<PullToRefreshPage> createState() =>
      _PullToRefreshPageState();
}

class _PullToRefreshPageState extends State<PullToRefreshPage> {
  List<String> _list = ['A', 'B', 'C', 'D'];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pull To Refresh'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: RefreshIndicator(
        onRefresh: () async {
          // ここにRefreshしたときの更新処理を入れる
        },
        child: ListView.builder(
          itemCount: _list.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Center(
                child: Text(_list[index]),
              ),
            );
          },
        ),
      ),
    );
  }
}

Discussion