Flutter Scrollable Stack with Height greater than

2019-06-23 19:34发布

问题:

I have a widget hierarchy where SingleChildScrollView is the parent with a Stack as the child, the Stack has two children, if the Second child goes beyond the screen height its height gets clipped. According to docs the stack occupies size according to a Non-Positioned child. So that means we have to explicitly give a height to the Stack, but this height is arbitrary and it won't wrap the contents inside. My main aim is to wrap the SingleChildScrollView height rather than having empty space at bottom.

SingleChildScrollView(
    child: Container(
      height: MediaQuery.of(context).size.height + 150,
      child: SafeArea(
        bottom: false,
        child: Stack(
           fit: StackFit.expand,
          children: <Widget>[
              Container(height:MediaQuery.of(context).size.height * .35,),
              Positioned(top: top: MediaQuery.of(context).size.height * .35 +
                  MediaQuery.of(context).viewInsets.top,..)
                 ...]))))

[![image][1]][1]

[1]: https://i.stack.imgur.com/ZnoP0.png

回答1:

Solution #1

Do let me know if this isn't what you were looking for.

void main() => runApp(MaterialApp(home: HomePage()));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Container(
            padding: EdgeInsets.only(top: 44, left: 24, right: 24, bottom: 20),
            color: Colors.deepPurpleAccent,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Row(
                  children: <Widget>[
                    IconButton(
                      icon: Icon(Icons.arrow_back),
                      onPressed: () {},
                      color: Colors.white,
                    ),
                    Spacer(),
                    IconButton(
                      icon: Icon(Icons.more_vert),
                      onPressed: () {},
                      color: Colors.white,
                    ),
                  ],
                ),
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Container(color: Colors.white, width: 100, height: 100),
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 12.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          _myText("Your name", 16),
                          _myText("24 years old", 14),
                          SizedBox(height: 6),
                          _myText("Martial status", 16),
                          _myText("Unmarried", 14),
                          SizedBox(height: 6),
                          Container(padding: EdgeInsets.all(4), color: Colors.blue, child: _myText("PLUS PLAN - 1 DAY LEFT", 12)),
                          SizedBox(height: 12),
                        ],
                      ),
                    ),
                  ],
                ),
                SizedBox(
                  width: double.maxFinite,
                  child: OutlineButton(
                    borderSide: BorderSide(color: Colors.white, width: 2),
                    onPressed: () {},
                    child: _myText("CHANGE PLAN", 16),
                  ),
                ),
                Text(
                  "Higher plans give you more connects",
                  style: TextStyle(fontSize: 10, color: Colors.white70),
                ),
              ],
            ),
          ),
          Expanded(
            child: ListView(
              children: <Widget>[
                _buildCard1(),
                _buildCard(size: 70, color: Colors.deepOrange),
                _buildCard(size: 80, color: Colors.purple),
                _buildCard(size: 90, color: Colors.pink),
                _buildCard(size: 100, color: Colors.grey),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _myText(String data, double size) => Text(data, style: TextStyle(fontSize: size, color: Colors.white));

  Widget _buildCard1() {
    return Card(
      elevation: 4,
      margin: EdgeInsets.all(12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text("PROFILE DETAILS"),
          ),
          Placeholder(fallbackHeight: 200),
          Divider(),
          SizedBox(
            width: double.maxFinite,
            child: FlatButton(
              onPressed: () {},
              child: Text("UPDATE MY PROFILE"),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildCard({double size, Color color}) {
    return Card(
      margin: EdgeInsets.all(12),
      child: Container(height: size, color: color,),
    );
  }
}

Solution # 2

Is this what you were looking for? (Here I only modified above build() method, rest of the method remains same.

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.deepPurpleAccent,
    body: SafeArea(
      child: ListView(
        children: <Widget>[
          Container(
            padding: EdgeInsets.only(top: 12, left: 24, right: 24, bottom: 20),
            color: Colors.deepPurpleAccent,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Row(
                  children: <Widget>[
                    IconButton(
                      icon: Icon(Icons.arrow_back),
                      onPressed: () {},
                      color: Colors.white,
                    ),
                    Spacer(),
                    IconButton(
                      icon: Icon(Icons.more_vert),
                      onPressed: () {},
                      color: Colors.white,
                    ),
                  ],
                ),
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Container(color: Colors.white, width: 100, height: 100),
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 12.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          _myText("Your name", 16),
                          _myText("24 years old", 14),
                          SizedBox(height: 6),
                          _myText("Martial status", 16),
                          _myText("Unmarried", 14),
                          SizedBox(height: 6),
                          Container(padding: EdgeInsets.all(4), color: Colors.blue, child: _myText("PLUS PLAN - 1 DAY LEFT", 12)),
                          SizedBox(height: 12),
                        ],
                      ),
                    ),
                  ],
                ),
                SizedBox(
                  width: double.maxFinite,
                  child: OutlineButton(
                    borderSide: BorderSide(color: Colors.white, width: 2),
                    onPressed: () {},
                    child: _myText("CHANGE PLAN", 16),
                  ),
                ),
                Text(
                  "Higher plans give you more connects",
                  style: TextStyle(fontSize: 10, color: Colors.white70),
                ),
              ],
            ),
          ),
          Container(
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.horizontal(left: Radius.circular(30), right: Radius.circular(30))
            ),
            child: Column(
              children: <Widget>[
                _buildCard1(),
                _buildCard(size: 70, color: Colors.deepOrange),
                _buildCard(size: 80, color: Colors.purple),
                _buildCard(size: 90, color: Colors.pink),
                _buildCard(size: 100, color: Colors.grey),
              ],
            ),
          ),
        ],
      ),
    ),
  );
}

Solution #3

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: SafeArea(
      child: DecoratedBox(
        decoration: BoxDecoration(image: DecorationImage(image: AssetImage("your_image_here"), fit: BoxFit.cover)),
        child: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              expandedHeight: 300,
              flexibleSpace: FlexibleSpaceBar(
                collapseMode: CollapseMode.pin,
                background: Container(
                  decoration: BoxDecoration(image: DecorationImage(image: AssetImage("your_image_here"), fit: BoxFit.cover)),
                  padding: EdgeInsets.only(top: 12, left: 24, right: 24, bottom: 20),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Row(
                        children: <Widget>[
                          IconButton(
                            icon: Icon(Icons.arrow_back),
                            onPressed: () {},
                            color: Colors.white,
                          ),
                          Spacer(),
                          IconButton(
                            icon: Icon(Icons.more_vert),
                            onPressed: () {},
                            color: Colors.white,
                          ),
                        ],
                      ),
                      Row(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          Container(color: Colors.white, width: 100, height: 100),
                          Padding(
                            padding: const EdgeInsets.symmetric(horizontal: 12.0),
                            child: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: <Widget>[
                                _myText("Your name", 16),
                                _myText("24 years old", 14),
                                SizedBox(height: 6),
                                _myText("Martial status", 16),
                                _myText("Unmarried", 14),
                                SizedBox(height: 6),
                                Container(padding: EdgeInsets.all(4), color: Colors.blue, child: _myText("PLUS PLAN - 1 DAY LEFT", 12)),
                                SizedBox(height: 12),
                              ],
                            ),
                          ),
                        ],
                      ),
                      SizedBox(
                        width: double.maxFinite,
                        child: OutlineButton(
                          borderSide: BorderSide(color: Colors.white, width: 2),
                          onPressed: () {},
                          child: _myText("CHANGE PLAN", 16),
                        ),
                      ),
                      Text(
                        "Higher plans give you more connects",
                        style: TextStyle(fontSize: 10, color: Colors.white70),
                      ),
                    ],
                  ),
                ),
              ),
            ),
            SliverList(
              delegate: SliverChildListDelegate(
                [
                  Container(
                    decoration: BoxDecoration(
                        color: Colors.orange,
                        borderRadius: BorderRadius.horizontal(
                          left: Radius.circular(30),
                          right: Radius.circular(30),
                        )),
                    child: Column(
                      children: <Widget>[
                        _buildCard1(),
                        _buildCard(size: 100, color: Colors.deepOrange),
                        _buildCard(size: 80, color: Colors.purple),
                        _buildCard(size: 100, color: Colors.pink),
                        _buildCard(size: 180, color: Colors.grey),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    ),
  );
}