Re:Vue

スクロールできるリスト


ListView/SingleChildScrollView


1. はじめに

リスト表示、それも画面からスクロールできるヴィジェットを2つ。ListViewSingleChildScrollView

今回扱うファイルは下記ディレクトリである。

プロジェクトディレクトリ
│
│── lib
│   │──main
│      │── first_page.dart
│      │── main.dart
│      │── second_page.dart
│

2. ListView

直線的に配置された、スクロール可能なリストが作成出来るヴィジェット

body: Center(
  child: ListView(
    reverse: true, //要素を逆にすることも可
    children: <Widget>[
      const Text('こんにちは'),
      const Text('こんばんは'),
      Container(width: 200, height: 1000, color: Colors.red)
    ],
  ),
),

■ ListView.builder

表示したい要素が動的な場合はListView.builderヴィジェットを使うと良い

body: Center(
      child: ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          return Container(
              child: Text('$index'),
              alignment: Alignment.center,
              width: 200,
              height: 100,
              color: Colors.red,
              margin: const EdgeInsets.symmetric(vertical: 10));
        },
      ),
    ),

■ ListView.separated

1行ごとに何かしらの要素を加えたい場合

body: Center(
  child: ListView.separated(
    separatorBuilder: (context, item) {
      return Container(color: Colors.blue, height: 20);
    },
    itemCount: 10,
    itemBuilder: (context, index) {
      return Container(
          child: Text('$index'),
          alignment: Alignment.center,
          width: 200,
          height: 100,
          color: Colors.red,
          margin: const EdgeInsets.symmetric(vertical: 10));
    },
  ),
),

2. SingleChildScrollView

子ヴィジェットでColumnやRowと一緒に用いられる。例えば、SingleChildScrollViewの中にColumnの子ヴィジェットがあれば、縦にはみ出すときに上下スクロールが出来るようになる。Rowの場合は左右スクロールが可能になる。

      body: Center(
          child: SingleChildScrollView(
              scrollDirection: Axis.vertical,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  const Text('こんにちは'),
                  const Text('こんばんは'),
                  Container(
                    width: 200,
                    height: 1000,
                    color: Colors.red,
                  )
                ],
              ))
          ),

3. とりあえず、練習でこんなやつを。

べたーとはるだけ。

■ main.dart

ここはとくに。

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

//アプリの起動
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.lightGreen,
      ),
      home: FirstPage(),
    );
  }
}

■ first_page.dart

スクロールできるように無駄にテキストが長い。

import 'package:flutter/material.dart';
import 'package:flutter_sample/second_page.dart';

class FirstPage extends StatelessWidget {
  FirstPage({Key? key}) : super(key: key);
  String description = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Page1")),
      body: Center(
        child: ListView(
          reverse: false, //要素を逆にすることも可
          children: <Widget>[
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text(
                'List Viewのいろいろ',
                textAlign: TextAlign.center,
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
              ),
            ),
            SizedBox(
              width: 200,
              height: 200,
              child: Image.network('https://picsum.photos/250?image=9'),
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Text('List Viewは'),
                Text('直線的に配置されたスクロール可能な'),
                Text('リストが作れる。'),
                Text('表示する要素が動的な場合'),
                Text('ListView.builderを使うと良い'),
                Text('表示する要素が事前に把握しており、'),
                Text('且つ一行ごとに何か要素を差し込みたい場合は'),
                Text('ListView.separated'),
                Text('を使うと良い'),
                Text('もう一度言います(再放送)'),
                Text('List Viewは'),
                Text('直線的に配置されたスクロール可能な'),
                Text('リストが作れる。'),
                Text('表示する要素が動的な場合'),
                Text('ListView.builderを使うと良い'),
                Text('表示する要素が事前に把握しており、'),
                Text('且つ一行ごとに何か要素を差し込みたい場合は'),
                Text('ListView.separated'),
                Text('を使うと良い'),
                Text('もう一度言います(再々放送)'),
                Text('List Viewは'),
                Text('直線的に配置されたスクロール可能な'),
                Text('リストが作れる。'),
                Text('表示する要素が動的な場合'),
                Text('ListView.builderを使うと良い'),
                Text('表示する要素が事前に把握しており、'),
                Text('且つ一行ごとに何か要素を差し込みたい場合は'),
                Text('ListView.separated'),
                Text('を使うと良い'),
              ],
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => SecondPage(),
                      fullscreenDialog: true),
                );
              },
              child: const Text("Go to Page2"),
            ),
          ],
        ),
      ),
    );
  }
}

■ second_page.dart

リストの項目間で separatorBuilderで見られるように戻るボタンを挟む(珍)。

import 'package:flutter/material.dart';

class SecondPage extends StatelessWidget {
  const SecondPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Page2")),
      body: SizedBox(
        child: ListView.separated(
          separatorBuilder: (context, item) {
            return ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: const Text("Back"),
            );
          },
          itemCount: 10,
          itemBuilder: (context, index) {
            return Container(
                alignment: Alignment.center,
                width: 200,
                height: 100,
                color: Colors.lime,
                margin: const EdgeInsets.symmetric(vertical: 10),
                child: Text('$index'));
          },
        ),
      ),
    );
  }
}

4. おわりに

UdemyのFlutterラボの講座に依存しつつ、公式ドキュメントを含めた肉付けをしようとしたが、案外さっぱり目。

参考↓