Anoop Thiruonam
Anoop Thiruonam

Reputation: 2872

Handling stack when the size of the children exceeds screen size

It is very easy to control the layout using Stack when the children's size is less than that of the screen. But when the children's height is greater than that of the screen size, you will need to use SingleChildScrollView. But if I use this, the whole screen goes white and produces the error shown below.

How can I handle the layout when using Stack & SingleChildScrollView in these circumstances. Any help is greatly appreciated. Thank you.

Sample code

import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          child: SingleChildScrollView(
            child: Stack(
              fit: StackFit.expand,
              children: [
                _Background(),
                Positioned(left: 0, top: 100, child: WidgetA()),
                Positioned(left: 0, top: 270, child: WidgetB()),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _Background extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
    );
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: randomHeight(),
      width: MediaQuery.of(context).size.width,
      color: Colors.purple,
      child: Center(
        child: Text('Widget A'),
      ),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 250,
      width: MediaQuery.of(context).size.width,
      color: Colors.yellow,
      child: Center(
        child: Text('Widget B'),
      ),
    );
  }
}

Error

════════ Exception caught by rendering library ═════════════════════════════════
RenderBox was not laid out: RenderRepaintBoundary#2e73f relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1940 pos 12: 'hasSize'

The relevant error-causing widget was
Scaffold
lib/main.dart:11
════════════════════════════════════════════════════════════════════════════════

Upvotes: 1

Views: 952

Answers (3)

Patrick Kelly
Patrick Kelly

Reputation: 1009

Cause:

The SingleChildScrollView Provides Infinite Space.

The stack sizes itself to contain all the non-positioned children, which are positioned according to alignment (which defaults to the top-left corner in left-to-right environments and the top-right corner in right-to-left environments). The positioned children are then placed relative to the stack according to their top, right, bottom, and left properties.

The widget inflates forever.

It will also cause problems with the StackRender Algorithm as that will deal with the Zenith.

Read more in the api documentation here.

Solution give it a Constraint such as a SizedBox();

Upvotes: 2

Moaid ALRazhy
Moaid ALRazhy

Reputation: 1744

first the whole screen goes white because the StackFit.expand tell the stack to expand as much as possible and since it is inside SingleChildScrollView that is infinity and can't be handled.

second is that the stack height is defined based on its children and the Position widget height is not calculated , like css position:absolute; if you are familiar with that , so the remaining is your _Background whcih is the widget that define the height of the stack ..

so now SingleChildScrollView and its child has (screen height) height = no scrolling and to solve this we have to specify height enough for our positioned widgets to appear in and for our stack to be able to scroll in.

How to fix

first in your stack change fit to

 child: Stack(
            fit: StackFit.loose,

second your background which is responsible for the height as mentioned above

class _Background extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: MediaQuery.of(context).size.height + 250, // <-- change this
      width: MediaQuery.of(context).size.width,
    );
  }
}

Upvotes: 1

Sam Jeffrey
Sam Jeffrey

Reputation: 46

Wrap your stack with a container and define it's height and width with MediaQuery, then wrap the container with a column.

Upvotes: 1

Related Questions