Flutter SingleChildScrollView内でListViewを使い、全画面でスクロールしたい
実現したいこと
動画のように、SingleChildScrollView内でListViewを使い、全画面でスクロールしたいです。
(ListViewはスクロールされず固定で、画面全体をスクロースしたい。Instagramのマイページみたいなイメージ)
動画を見るとできてるかのように見えますが、なぜか一番最後のCard
の下途切れております。。。
これを解消したいです!
なんでCardの下が途切れてるねん。。。
— 高卒プログラマーげんと (@gento34165638) June 6, 2021
まじで意味がわかりませんな😥 pic.twitter.com/igkWVa7gAd
該当のソース
MyPageScreen>MyPageMovies>MyPageMovieCard
というようにネストされています。
・MyPageScreen→画面全体
・MyPageMovies→映画一覧を表示させるWidget
・MyPageMovieCard→映画のCard1つ1つ
こんな感じです。
※APIから値を取得したりしている部分は省きます
MyPageScreen
class MyPageScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
body: SingleChildScrollView(
child: Container(
// ここでheightを指定しないとエラーになる
height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.all(30),
child: Column(
children: <Widget>[
// MyPageView(), 関係ないため除外
Padding(
padding: EdgeInsets.only(
top: 3 * SizeConfig.blockSizeVertical,
bottom: 3 * SizeConfig.blockSizeVertical,
),
child: Text(
'My Movies',
style: Theme.of(context).textTheme.headline6,
),
),
MyPageMovies(),
],
),
),
),
);
}
}
SingleChildScrollView
直下にあるContainer
で高さを指定しないと壮大なエラーに遭遇します。。
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
// 省略
Updated layout information required for _RenderScrollSemantics#fe738 NEEDS-LAYOUT NEEDS-PAINT to calculate semantics.
'package:flutter/src/rendering/object.dart':
Failed assertion: line 2658 pos 12: '!_needsLayout'
MyPageMovies
class MyPageMovies extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userId = _firebaseAuth.currentUser.uid;
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('users/${userId}/movies').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error),
);
}
if (snapshot.hasData) {
return Expanded(
child: ListView.builder(
itemCount: snapshot.data.docs.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Column(
children: <Widget>[
MyPageMovieCard(
snapshot.data.docs[index].data()['id'],
snapshot.data.docs[index].data()['title'],
),
],
);
},
),
);
}
return Center(child: CircularProgressIndicator());
});
}
}
ListView.builder
でスクロールさせないために、下記2つを追加。
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
MyPageMovieCard
class MyPageMovieCard extends StatelessWidget {
final int id;
final String title;
MyPageMovieCard(this.id, this.title);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: getMyMovie(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error),
);
}
if (snapshot.hasData) {
final posterPath = snapshot.data['poster_path'];
return InkWell(
borderRadius: BorderRadius.circular(10),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Row(
children: <Widget>[
Image.network(
'https://image.tmdb.org/t/p/w154/${posterPath}',
),
Expanded(
child: Container(
padding: const EdgeInsets.all(10),
child: Container(
width: double.infinity,
child: Text(
title,
style: Theme.of(context).textTheme.headline6,
textAlign: TextAlign.left,
),
),
),
),
],
),
),
);
}
return Center(child: CircularProgressIndicator());
});
}
}
自分で試したこと
ListViewをスクロール可能にする
return Expanded(
child: ListView.builder(
itemCount: snapshot.data.docs.length,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return Column(
こうすると最後までCard
が途切れることなく表示されます。
でもこれだとSingleChildScrollView
でもスクロールできて、ListView
でもスクロールできてしまうので、、、。
LayoutBuilderを使用
👆を参考に下記のコードを試しましたが、全く同じエラーでダメでした。。。
class MyPageScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
// MyPageView(),
Padding(
padding: EdgeInsets.only(
top: 3 * SizeConfig.blockSizeVertical,
bottom: 3 * SizeConfig.blockSizeVertical,
),
child: Text(
'My Movies',
style: Theme.of(context).textTheme.headline6,
),
),
MyPageMovies(),
],
),
),
),
),
),
);
}
}