Dart

42.【AppleMusicクローン】FlutterのPageViewを使って横スクロールのPageScrollを実現する

キーワードは PageView です。
今回は AppleMusicクローン の最初のセクションを実装していきます。

最終的に出来上がるデザインはこちらになります。

最初は ListView の Axis.horizontal を使って再現させようとしましたが挫折しました。
どうしても Item の index 単位での横スクロールができなかったので諦めようかと思いましたが
これを実現できるウィジェットが見つかりました。

PageView について

それでは PageView の使い方について紹介します。

PageView.builder(
            itemCount: [横に並べるウィジェットの個数(int)],
            controller: [PageControllerのインスタンス],
            itemBuilder: (BuildContext context, int itemIndex) {
              return [一つ当たりのwidget];
            },
          )

このように書くことで [一つ辺りのwidget] で設定したウィジェットを itemCount 分生成して ListView に並べることができます。

ソースコード

それでは、PageView を利用して最初のセクションを作成します。
最終的に出来上がるソースコードは次のようになります。

content_sliver_list.dart

import 'package:flutter/material.dart';

class ContentSliverList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
          if (index % 2 == 0) {
            return Padding(
              padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
              child: Divider(
                color: Colors.black,
              ),
            );
          } else {
            return _buildHorizontalPageView(context, 4);
          }
        },
        childCount: 20,
      ),
    );
  }

  Widget _buildHorizontalPageView(BuildContext context, int itemCount) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        SizedBox(
          // you may want to use an aspect ratio here for tablet support
          height: 300.0,
          child:
          PageView.builder(
            itemCount: itemCount,
            controller: PageController(viewportFraction: 0.9),
            itemBuilder: (BuildContext context, int itemIndex) {
              return _buildHorizontalItem(context, itemCount, itemIndex);
            },
          )
          ,
        )
      ],
    );
  }

  Widget _buildHorizontalItem(
      BuildContext context, int carouselIndex, int itemIndex) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 5.0),
      child: Column(
        children: <Widget>[
          Align(
            alignment: Alignment.centerLeft,
            child: Text(
              'ニューアルバム',
              style: TextStyle(color: Colors.red, fontSize: 10, fontWeight: FontWeight.w700),
            ),
          ),
          Align(
            alignment: Alignment.centerLeft,
            child: Text('Sparkle',
                style: TextStyle(color: Colors.black, fontSize: 15, fontWeight: FontWeight.w500)
            ),
          ),
          Align(
            alignment: Alignment.centerLeft,
            child: Text('iri',
                style: TextStyle(color: Colors.grey, fontSize: 15, fontWeight: FontWeight.w500)
            ),
          ),
          Container(
            height: 226,
            decoration: BoxDecoration(
              color: Colors.grey,
              borderRadius: BorderRadius.all(Radius.circular(5.0)),
            ),
          )
        ],
      ),
    );
  }
}

一つあたりのウィジェットは簡単なレイアウトで組んでみました。
これをビルドすると iOS の UIScrollView の pagingenabledtrue にしたときのような挙動を実現できます。

この PageView を見つけるまでが非常に大変でしたが実際に使ってみること自体はとても簡単でした。
iOS の index 単位のページングスクロールを実現したい場合は是非 PageView を使ってみてください。

ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。