はじめに
いい感じのスクロール画面を作ろうとした時に大体使うであろうsliver
系のウィジェット。
代表的なのはSliverAppBar
このsliverの中でContainerを使いたい場面は多々あるかと。
例えばSliverList
に背景色をつけようとしたり。
が、、、sliverに対してはsliverしか使えないという原則によって、めちゃ困惑しました。。。
sliverとは
Sliver(細長い小片)とはスクロール可動領域の一部分を細かくカスタマイズできるウィジェット群です。
Sliverとつくウィジェットは複数あり、普通のウィジェットとは異なるようです。
Child(普通のウィジェット)ウィジェット:
Childウィジェットは通常のウィジェットです。Container、Text、Image、Row、Columnなどの一般的なウィジェットがこれに該当します。
通常のウィジェットツリーの中で使います。例えば、画面の一部分を作成するためにChildウィジェットを使うことがあります。
Sliver(スリバー)ウィジェット:
Sliverウィジェットは、スクロール可能なリストやCustomScrollView内で使用される特別なウィジェットです。
一般的に、CustomScrollView内でスクロール可能な要素を作成するために使用されます。これにはSliverAppBar、SliverList、SliverGridなどが含まれます。
この理解はsliverを扱う上で非常に重要です!
SliverListに背景色をつけたい
仮に👇のように画面全体ではなく各Listごとに装飾をしたいとします。
普通に考えるとこんなコードになります。
child: Scaffold(
body: const CustomScrollView(
slivers: [
_SliverAppBar(),
Container(
// decorationで装飾
child: _SliverList(),
),
Container(
// decorationで装飾
child: _SliverList(),
),
],
),
),
しかしこれだとだめなんです。。。
なぜならslivers
にはsliver系ウィジェットしか使えないから!
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building Expanded(flex: 1):
A RenderRepaintBoundary expected a child of type RenderBox but received a child of type
RenderSliverList.
RenderObjects expect specific types of children because they coordinate with their children during
layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a
RenderSliver does not understand the RenderBox layout protocol.
The RenderRepaintBoundary that expected a RenderBox child was created by:
RepaintBoundary ← IndexedSemantics ← _SelectionKeepAlive ←
NotificationListener<KeepAliveNotification> ← KeepAlive ← AutomaticKeepAlive ← KeyedSubtree ←
SliverList ← _SliverList ← SliverPadding ← Viewport ← IgnorePointer-[GlobalKey#c987a] ← ⋯
The RenderSliverList that did not match the expected child type was created by:
SliverList ← Expanded ← RepaintBoundary ← IndexedSemantics ← _SelectionKeepAlive ←
NotificationListener<KeepAliveNotification> ← KeepAlive ← AutomaticKeepAlive ← KeyedSubtree ←
SliverList ← _SliverList ← SliverPadding ← ⋯
こんな感じでエラーになります
RenderSliver does not understand the RenderBox layout protocol.
要はsliver
の中で普通のウィジェットは使えない、ということを言われてます
SliverPadding
はありますがSliverContainer
というのはなんと存在しません!!
じゃどうやって背景色つけたり角を丸くしたりするの???となる訳です。。。
sliverの中でContainerを再現するにはこれだ!
DecoratedSliver
なるものがいつの間にやら誕生してました!!
これを使うことでContainerと同じようなことができます。
child: Scaffold(
body: const CustomScrollView(
slivers: [
_SliverAppBar(),
DecoratedSliver(
// decorationで装飾
sliver: _SliverList(),
),
DecoratedSliver(
// decorationで装飾
sliver: _SliverList(),
),
],
),
),
sliverの中ではExpandedも使えないので、なかなか扱いがわかってくるまで大変です
参考