mzimmermann
mzimmermann

Reputation: 1072

How to achieve expansion of a widget in both vertical (height) and horizontal (width) direction

The code below lays out a chart in which I'd need to achieve for the chart to be expanded in both vertical (height) and horizontal (width) direction. The suggested method (e.g. https://docs.flutter.io/flutter/widgets/Row-class.html) is to use Expanded in Row or Column.

The chart widget I am trying to expand extends CustomPaint, with no children, everything is painted using a CustomPainter on canvas, in the CustomPainter.paint(canvas, size).

This code

return new Scaffold(
  appBar: new AppBar(
    title: new Text(widget.title),
  ),
  body: new Center(    
    child: new Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        new Text(
          'vvvvvvvv:',
        ),
        new RaisedButton(
          color: Colors.green,
          onPressed: _chartStateChanger,
        ),
        new Text(
          'vvvvvvvv:',
        ),    
        new Expanded( // Expanded in Column, no expansion vertically 
          child: new Row(
            children: [
              new Text('>>>'),    
              new Expanded(// Expanded in Row, expands horizontally
                child: new Chart(  // extends CustomPaint
                  // size: chartLogicalSize,
                  painter: new ChartPainter( // extends CustomPainter
                    chartData: _chartData,
                    chartOptions: _chartOptions,
                  ),
                ),
              ),
              new Text('<<<'),
            ],
          ),  // row
        ),
        new Text('^^^^^^:'),
        new RaisedButton(
          color: Colors.green,
          onPressed: _chartStateChanger,
        ),
      ],
    ),
  ),
);

result looks like this: (code of ChartPainter is not shown for brevity) result of the above code

Inside the ChartPainter.paint(canvas, size) there is a print() printing the size.

print(" ### Size: paint(): passed size = ${size}");

The result from the paint->print above is:

I/flutter ( 4187): ### Size: paint(): passed size = Size(340.0, 0.0)

The print along with the image shows, that the width expansion on the row level was passed to the CustomPainter.print(canvas, size) (width = 340.0), but the height expansion on the column did not get passed to the custom painter print (height = 0.0). Although the result shows that the row did get it's expanded height, if was not passed inside the row to the CustomPainter - 0 height was received.

What do I need to change to achieve the height expansion as well?

Thanks

Upvotes: 38

Views: 67773

Answers (4)

CopsOnRoad
CopsOnRoad

Reputation: 267534

Use SizedBox.expand:

SizedBox.expand(
  child: YourWidget() // Could be anything like `Column`, `Stack`...
)

Upvotes: 15

Natwar Singh
Natwar Singh

Reputation: 2275

There is a better way than nesting Row, Expanded and Column widget. You can use the Container widget with Constraints to BoxConstraints.expand().

Example Code:

    Widget build(BuildContext context) {
      return Container(
        constraints: BoxConstraints.expand(), 
        child: FutureBuilder(
          future: loadImage(),
          builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
            switch(snapshot.connectionState) {
              case ConnectionState.waiting : 
                return Center(child: Text("loading..."),);
              default:
                if (snapshot.hasError) {
                  return Center(child: Text("error: ${snapshot.error}"),);
                } else {
                  return ImagePainter(image: snapshot.data);
                }
              }
            },
          ),
      );
    }

Upvotes: 21

Artem Panfilov
Artem Panfilov

Reputation: 39

For those who struggled to get gradient together with Material behaviour:

return new Stack(
  children: <Widget>[
    new Material(
      elevation: 10,
      borderRadius: new BorderRadius.all(new Radius.circular(30.0)),
      color: Colors.transparent,
      child: new Container(
        constraints: BoxConstraints.expand(height: 50),
      ),
    ),
    new Container(
      constraints: BoxConstraints.expand(height: 50),
      decoration: BoxDecoration(
        borderRadius: new BorderRadius.all(new Radius.circular(30.0)),
        gradient: new LinearGradient(
            colors: [color1, color2],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter),
      ),
      child: new FloatingActionButton.extended(
        backgroundColor: Colors.transparent,
        foregroundColor: Colors.transparent,
        highlightElevation: 0,
        elevation: 0,
        onPressed: () {
          onPressed();
        },
        label: new Text(this.caption,
            textAlign: TextAlign.center,
            style: Theme.of(context).textTheme.body1),
      ),
    )
  ],
)

Upvotes: 3

Collin Jackson
Collin Jackson

Reputation: 116728

Here is a reduced test case for the issue you are seeing. The solution is to give your Row a crossAxisAlignment of CrossAxisAlignment.stretch. Otherwise it will try to determine the intrinsic height of your CustomPaint which is zero because it doesn't have a child.

import 'package:flutter/material.dart';

// from https://stackoverflow.com/questions/45875334/how-to-achieve-expansion-of-a-widget-in-both-vertical-height-and-horizontal-w

class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // NOT using crossAxisAlignment: CrossAxisAlignment.stretch => width = 222.0, height=0.0
    // using crossAxisAlignment: CrossAxisAlignment.stretch     => width = 222.0, height=560.0
    print("width = ${size.width}, height=${size.height}");
    canvas.drawRect(Offset.zero & size, new Paint()..color = Colors.blue);
  }

  @override
  bool shouldRepaint(MyCustomPainter other) => false;
}
void main() {
  runApp(new MaterialApp(
    home: new Scaffold(
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text('Above Paint'),
            // Expanded - because we are in Column, expand the
            //            contained row's height
            new Expanded(
              child: new Row(
                // The crossAxisAlignment is needed to give content height > 0
                //   - we are in a Row, so crossAxis is Column, so this enforces
                //     to "stretch height".
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  new Text('Left of Paint'),
                  // Expanded - because we are in Row, expand the
                  //           contained Painter's width
                  new Expanded(
                    child: new CustomPaint(
                      painter: new MyCustomPainter(),
                    ),
                  ),
                  new Text('Right of Paint'),
                ],
              ),
            ),
            new Text('Below Paint'),
          ],
        )
    ),
  ));
}

Upvotes: 62

Related Questions