Flutter stack layout container use remaining height

Viewed 2122

I'm starting with Flutter.

I'm building a layout to look like

enter image description here

I'm using Stack to build this layout, where the part in background color is another Stack child with parent Container height to a fixed value.

The code I have written till now is

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:whatsappwithoutcontact/components/form_fields.dart';
import 'package:whatsappwithoutcontact/screens/info/info-screen.dart';


class MessageScreen extends StatefulWidget {
  @override
  _MessageScreenState createState() => _MessageScreenState();
}

class _MessageScreenState extends State<MessageScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WhatsApp without Contact'),
        backgroundColor: Colors.transparent,
        elevation: 0.0,
        actions: [
          IconButton(
            icon: Icon(Icons.info),
            onPressed: _onInfoPressed,
          )
        ],
      ),
      extendBodyBehindAppBar: true,
      body: MessageContainer()
    );
  }

  void _onInfoPressed() {
    Navigator.of(context).push(
      MaterialPageRoute<void> (
        builder: (BuildContext context) {
          return InfoScreen();
        }
      )
    );
  }
}

class MessageContainer extends StatefulWidget {
  @override
  _MessageContainerState createState() => _MessageContainerState();
}

class _MessageContainerState extends State<MessageContainer> {
  static const double avatarRadius = 35;
  static const double titleBottomMargin = (avatarRadius * 2) + 18;
  static const double _headerHeight = 350.0;
  final _formKey = GlobalKey<FormState>();
  final _messageFieldFocusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Stack(
        children: [
          Container(
            height: _headerHeight,
            child: Stack(
              children: <Widget>[
                Container(
                  child: ClipPath(
                    clipper: HeaderClipper(avatarRadius: avatarRadius),
                    child: CustomPaint(
                      size: Size(MediaQuery.of(context).size.width, _headerHeight),
                      painter: HeaderPainter(
                          color: Colors.green,
                          avatarRadius: avatarRadius
                      ),
                    ),
                  ),
                ),
                Positioned(
                  left: 0,
                  right: 0,
                  child: Container(
                    padding: EdgeInsets.only(top: 80.0),
                    margin: EdgeInsets.all(50.0),
                    child: Column(
                      children: <Widget>[
                        FormTextField(
                          labelText: 'Country Code',
                          validator: (value) {
                            if (value.isEmpty) {
                              return 'Required';
                            }
                            return null;
                          }
                        ),
                        SizedBox(height: 15.0,),
                        FormTextField(
                          labelText: 'Phone Number',
                          validator: (value) {
                            if (value.isEmpty) {
                              return 'Required';
                            }
                            return null;
                          },
                        )
                      ],
                    ),
                  ),
                ),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: CircleAvatar(
                    radius: avatarRadius,
                    backgroundColor: Colors.green,
                    child: IconButton(icon: Icon(Icons.message), onPressed: _onAddMessageButtonClick,),
                  ),
                )
              ],
            ),
          ),
          SingleChildScrollView(
            child: Padding(
              padding: EdgeInsets.symmetric(
                vertical: _headerHeight,
                horizontal: 50
              ),
              child: Column(
                children: [
                    TextFormField(
                      keyboardType: TextInputType.multiline,
                      maxLines: 4,
                      focusNode: _messageFieldFocusNode,
                      decoration: InputDecoration(
                        labelText: 'Message',
                        fillColor: Colors.white,
                        labelStyle: TextStyle(
                          color: _messageFieldFocusNode.hasFocus ? Colors.green : Colors.grey
                        ),
                        enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(
                            color: Colors.grey
                          )
                        ),
                        focusedBorder: OutlineInputBorder(
                          borderSide: BorderSide(
                            color: Colors.green
                          )
                        )
                      ),
                    )
                ],
              ),
            ),
          ),
        ],
      )
    );

  }
}

The first Container inside the first Stack is the green background part and SingleChildScrollView is the part below the green color background.

The SingleChildScrollView is making the lower part scrollable whereas I want it to be fixed and take up remaining space below the message icon in the center.

I tried using Container but then the Message input field is not displayed.

  1. How can I use the remaining space below the Stack layout?
  2. Is my layout structure good according to the design. I need suggestions on how to improve it, if not good.
1 Answers

Replace the first Stack widget with Column, now you can wrap your SingleChildScrollView widget into an Expanded widget, the Expanded widget works only inside Column and Row to fill the available space.

Don't forget to remove vertical padding from the Message input field.

Related