はじめに
ヘッダー付きのリストの実装をいくつか紹介します。
ヘッダー付きリストといっても、下図のようにリストのスクロールに合わせてヘッダーもスクロールするパターンとヘッダーは常に固定表示させておくパターンがあると思うのでそれぞれ紹介してみます。
ヘッダーもスクロール | ヘッダー固定 |
---|---|
![]() |
![]() |
実装
ヘッダー部分もスクロール
ヘッダー部分もスクロールするパターンについては以下3つの実装を紹介します。
- CustomScrollView + SliverToBoxAdapter
- CustomScrollView + SliverAppBar
- ListViewの先頭にヘッダーを配置
1. CustomScrollView + SliverToBoxAdapter
CustomScrollView
のslivers
プロパティの先頭にSliverToBoxAdapter
を配置してヘッダーとして扱う方法です。
リスト部分はSliverList
等を使って実装します。
class HeaderBySliverToBoxAdapter extends StatelessWidget {
const HeaderBySliverToBoxAdapter({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: ColoredBox(
color: Colors.blueGrey,
child: SizedBox(
height: 100,
width: double.infinity,
child: Center(
child: Text('Header'),
),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: 20,
(BuildContext context, int index) {
return ListTile(
title: Text(index.toString()),
);
},
),
),
],
);
}
}
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F658739%2Fe57d9467-42dc-0ba7-097a-21b638abe5da.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=5e734307b04e0642939f1f3fd416a8c8)
2. CustomScrollView + SliverAppBar
CustomScrollView
のslivers
プロパティの先頭にSliverAppBar
を配置してヘッダーとして扱う方法です。
1と同様に、リスト部分はSliverList
等を使って実装します。
class HeaderBySliverAppBar extends StatelessWidget {
const HeaderBySliverAppBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
const SliverAppBar(
expandedHeight: 100,
backgroundColor: Colors.blueGrey,
flexibleSpace: FlexibleSpaceBar(
title: Text('Header'),
centerTitle: true,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: 20,
(BuildContext context, int index) {
return ListTile(
title: Text(index.toString()),
);
},
),
),
],
);
}
}
SliverAppBarを使用するため、ヘッダー部分もスクロールするというより、ヘッダー部分は縮小して消えるような挙動になります。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F658739%2Ffe62dae4-b80a-915b-f36c-3ad12ee2a1d0.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=1f71b0b8823b41d115689db64e832487)
3. ListViewの先頭にヘッダーを配置
ListView
の先頭(indexが0)の時にヘッダーのWidgetを返すようにする方法です。
このような方法でも実現できますが、実際に実装する際はindex=0
はヘッダー部分が使用していることを考慮して、リスト部分のindexを調整する必要が出てくるためコードが煩雑になり微妙かもです...
class HeaderByListView extends StatelessWidget {
const HeaderByListView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
if (index == 0) {
return const ColoredBox(
color: Colors.blueGrey,
child: SizedBox(
height: 100,
width: double.infinity,
child: Center(
child: Text('Header'),
),
),
);
} else {
return ListTile(
title: Text(index.toString()),
);
}
},
);
}
}
挙動は1の「CustomScrollView + SliverToBoxAdapter」 と同じです。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F658739%2F149117b6-c475-10cf-4c36-9f883915085c.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=0c13ebd444438ba36c2d48bfe09534f5)
ヘッダー固定
ヘッダーを固定するパターンについては以下2つを紹介します。
- Columnで並べる
- CustomScrollView + SliverAppBar + pinnedプロパティ
1. Columnで並べる
単純にColumn
でヘッダー部分とListView
を並べて実装する方法です。
Column
の中でListView
を配置するため、ListView
はExpanded
等で囲っておく必要があることに注意。
class PinnedHeaderByColumn extends StatelessWidget {
const PinnedHeaderByColumn({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
const ColoredBox(
color: Colors.blueGrey,
child: SizedBox(
height: 100,
width: double.infinity,
child: Center(
child: Text('Header'),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(index.toString()),
);
},
),
)
],
);
}
}
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F658739%2F42163f11-293d-7a71-3f96-e7fa3ead12c8.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=37e17c2cfaeb224cb383816e720b8080)
2. CustomScrollView + SliverAppBar + pinnedプロパティ
ヘッダー部分もスクロールする方法で紹介した 「CustomScrollView + SliverAppBar」 において、 SliverAppBar
のpinned
プロパティにtrue
にセットすることで、ヘッダー部分を固定表示させることが可能です。
class PinnedHeaderBySliverAppBar extends StatelessWidget {
const PinnedHeaderBySliverAppBar({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
const SliverAppBar(
pinned: true,
expandedHeight: 100,
backgroundColor: Colors.blueGrey,
flexibleSpace: FlexibleSpaceBar(
title: Text('Header'),
centerTitle: true,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: 20,
(BuildContext context, int index) {
return ListTile(
title: Text(index.toString()),
);
},
),
),
],
);
}
}
SliverAppBarを使用している都合上縮小するような挙動をとります。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F658739%2Fe35b0caa-9a40-7a25-3e1d-0ea84c1ccfd6.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=9d4d1fcf3bc452066a672463dc61b971)
以上です。