LoginSignup
kokogento
@kokogento (ここ げんと)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Flutter SingleChildScrollView内でListViewを使い、全画面でスクロールしたい

実現したいこと

動画のように、SingleChildScrollView内でListViewを使い、全画面でスクロールしたいです。
(ListViewはスクロールされず固定で、画面全体をスクロースしたい。Instagramのマイページみたいなイメージ)
動画を見るとできてるかのように見えますが、なぜか一番最後のCardの下途切れております。。。
これを解消したいです!

該当のソース

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をスクロール可能にする

MyPageMovies
return Expanded(
              child: ListView.builder(
                itemCount: snapshot.data.docs.length,
                // shrinkWrap: true,
                // physics: NeverScrollableScrollPhysics(),
                itemBuilder: (BuildContext context, int index) {
                  return Column(

こうすると最後までCardが途切れることなく表示されます。
でもこれだとSingleChildScrollViewでもスクロールできて、ListViewでもスクロールできてしまうので、、、。

スクリーンショット 2021-06-06 22.56.47.jpg

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(),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
0

1Answer

SingleChildScrollViewによる「画面全体スクロール」でCardの内容を全て描画させたいということであれば、NeverScrollableScrollPhysics()である限りできないと思います。Cardをlazy描画しているのはListView.builderですので。

実現したい動作を実装するには、Card は lazy描画でない通常の方法で描画しておくしかないと思います。

0

Your answer might help someone💌