Moti Bartov
Moti Bartov

Reputation: 3592

Align widget center with AppBar bottom edge

I need to align a widget's center with the appbar bottom edge. So it will be located vertically half on the appbar and half on the page body.

Right now I've added the widget into the AppBar bottom: but it wont align with it's horizontal center line.

Currently It looks like this:

enter image description here

While i want that the center of the SelectEnvironment button along with the horizontal white line will 'sit' exactly on the bottom edge of the appBar

The code for the appBar is like this:

  class CustomAppBar extends AppBar {

     final Widget appBarActionButton;

     CustomAppBar({Widget title = AppUtils.EMPTY_TEXT_VIEW, this.appBarActionButton}): super(
        title: title,
        backgroundColor: Colors.blueGrey,
        elevation: 0,
        bottom: PreferredSize(
            child: Stack( //The stack holds the horizontal line and the button aligned cente
              alignment: Alignment.center,
              children: <Widget>[
                Container( //This is the horizontal line
                  color: Colors.GeneralDividerGray,
                  height: 1.0,
                ),
                Align(
                  child: Container(
                      child: appBarActionButton, //This is the button widget
                      ),
               )
          ],
        ),
        preferredSize: Size.fromHeight(4.0)),
      );
 }

If there a better way to achieve this by taking it outside of the appbar it's ok with me as long it will give the same effect.

Upvotes: 0

Views: 1983

Answers (2)

tbm98
tbm98

Reputation: 250

I think you should use Stack and Column like this

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

typedef void OnWidgetSizeChange(Size size);

class MeasureSize extends StatefulWidget {
  final Widget child;
  final OnWidgetSizeChange onChange;

  const MeasureSize({
    Key key,
    @required this.onChange,
    @required this.child,
  }) : super(key: key);

  @override
  _MeasureSizeState createState() => _MeasureSizeState();
}

class _MeasureSizeState extends State<MeasureSize> {
  @override
  Widget build(BuildContext context) {
    SchedulerBinding.instance.addPostFrameCallback(postFrameCallback);
    return Container(
      key: widgetKey,
      child: widget.child,
    );
  }

  var widgetKey = GlobalKey();
  var oldSize;

  void postFrameCallback(_) {
    var context = widgetKey.currentContext;
    if (context == null) return;

    var newSize = context.size;
    if (oldSize == newSize) return;

    oldSize = newSize;
    widget.onChange(newSize);
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Size s;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(
      children: [
        Column(
          children: [
            MeasureSize(
              onChange: (size) {
                setState(() {
                  s = size;
                });
              },
              child: AppBar(
                title: Text('title'),
              ),
            ),
            SizedBox(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height - (s?.height ?? 0.0),
                child: Center(child: Text('body')))
          ],
        ),
        Positioned(
          top: (s?.height ?? 0.0) - 16.0,
          child: Container(
            width: MediaQuery.of(context).size.width,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                    height: 32,
                    color: Colors.red[400],
                    padding: EdgeInsets.all(6),
                    child: Center(child: Text('Select Environment'))),
              ],
            ),
          ),
        )
      ],
    ));
  }
}

enter image description here

Upvotes: 1

emanuel sanga
emanuel sanga

Reputation: 945

The best way is to use Slivers via a widget like below:

  ScrollController scrollController = new ScrollController();
  return Stack(
    children: [
      NestedScrollView(
        controller: scrollController,
        headerSliverBuilder: (context, value){
          return [
//            list of widgets in here
          ];
        },
        body: Container(
          // here, your normal body goes
        ),
      ),
      Positioned(
        top: 50.0,
        left: 100.0,
        child: Container(
          // your centered widget here
        ),
      )
    ]
  );
}

Instead of using a normal appBar, you have to use a SliverAppBar

Upvotes: 1

Related Questions