16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CustomScrollViewを利用して一画面に複数のスクロール要素を構築する

Last updated at Posted at 2019-06-01

画面にリストやグリッド、画像など、様々な要素を挿入したい、という状況は結構あると思う。

しかし、リスト自体がスクロール要素を複数合わせると、思うように動いてくれない状況が発生した。

例えば下記のような要件を満たす画面を作成するとする。

  • 画像や文言など、規則性の無い要素を縦に並べる
  • 画面全体はスクロールできるようにする

イメージ

コードは下記のようになる

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue,),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    String img_src1 = 'https://example.com/img1.jpg';
    String img_src2 = 'https://example.com/img2.jpg';
    String img_src3 = 'https://example.com/img3.jpg';
    String img_src4 = 'https://example.com/img4.jpg';
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Text('example', style: TextStyle(fontSize: 30.0, color: Colors.amber),),
            Image.network(img_src1, height: 200,),
            Text('example', style: TextStyle(fontSize: 30.0, color: Colors.black45),),
            Image.network(img_src2, height: 200,),
            Text('example.example.example.example.example.example.', style: TextStyle(fontSize: 30.0, color: Colors.deepOrangeAccent),),
            Text('example.example.example.example.example.example.', style: TextStyle(fontSize: 30.0, color: Colors.teal),),
            Image.network(img_src3, width: 400,),
            Text('example', style: TextStyle(fontSize: 30.0, color: Colors.indigo),),
            Image.network(img_src4, width: 400,),
          ],
        ),
      ),
    );
  }
}

注意点は以下の通り

  • 規則性の無い要素を並べるので、ListView等ではなく、Columnを使用
    • 文言だけ or 写真だけ、ということであれば、ListViewの方が使い勝手はいいと思うが、今回は1内容に複数の要素が入っている
  • 画面からはみ出した分をスクロールできるように、SingleChildScrollViewで全体を囲む


他のスクロール要素を追加する

この画面に新しく文言をタイル状に表示するエリアを作ってみるために、下記のようなGridView要素を入れてビルドすると、例外が発生する。

main.dart
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    String img_src1 = 'https://example.com/img1.jpg';
    // 〜省略部分〜
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Text('example', style: TextStyle(fontSize: 30.0, color: Colors.amber),),
            // 〜省略部分〜
            Image.network(img_src4, width: 400,),
            // 新しく追加した部分↓
            GridView.count(
              crossAxisCount: 5,
              children: List.generate(100, (index) {
                return Center(
                  child: Text(
                    'Item $index',
                    style: Theme.of(context).textTheme.headline,
                  ),
                );
              }),
            )
          ],
        ),
      ),
    );
  }
}

これは、スクロール要素を入れ子にすることによって、縦の長さが無限になってしまうのを防ぐために、発生する例外とのこと。

CustomScrollViewでリストやグリッドを混在させる

CustomScrollViewとSliverを利用することで、リストやグリッドを好きに配置できるようになる。

main.dart
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    String img_src1 = 'https://example.com/img1.jpg';
    // 〜省略部分〜
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: CustomScrollView(
        slivers: <Widget>[
          SliverList(
            delegate: SliverChildListDelegate([
              Column(
                children: <Widget>[
                  Text('example', style: TextStyle(fontSize: 30.0, color: Colors.amber),),
                  // 〜省略部分〜
                  Image.network(img_src4, width: 400,)
                ]
              )
            ]),
          ),
          SliverGrid(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 5,
            ),
            delegate: SliverChildBuilderDelegate(
                  (BuildContext context, int index) {
                return Center(
                  child: Text(
                    'Item $index',
                    style: Theme.of(context).textTheme.headline,
                  ),
                );
              },
              childCount: 100,
            )
          ),
        ]
      ),
    );
  }
}

変更点と留意点は以下の通り

- `SingleChildScrollView`から`CustomScrollView`に変更する
- イメージや文言を格納していた`Column`要素を`SliverList`の中に入れる
- `GridView`部分は`SliverGrid`に変更

無事表示されるようになった。

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?