Search code examples
flutterflutter-layout

How to make a Flutter view with an item below a center in parent item?


I am trying to create a view that looks like this in Flutter. But, there is no concept of relative position in Flutter. Here is what I want to achieve.

enter image description here

The red rectangle is in the center of the screen, and the green rectangle is right below the red one.

In Android, I can easily do this with Constraint Layout,

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="#ff0000"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:background="#00ff00"
        app:layout_constraintEnd_toEndOf="@+id/view"
        app:layout_constraintTop_toBottomOf="@+id/view" />

</android.support.constraint.ConstraintLayout>

Can anyone suggest a good solution to this in Flutter?


Solution

  • @cynw

    Since both widgets are Texts and you don't know their heights until they are rendered, we have to calculate the height and re-render (rebuild) the widget.

    In my approach below, I add a SizedBox above the big Text to push it down to make sure it is laid out at the center. The bad thing in this approach is we have to re-build the widget.

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    void main() {
      SystemChrome.setEnabledSystemUIOverlays([]);
      runApp(MyStatefulApp());
    }
    
    class MyStatefulApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _MyStatefulAppState();
      }
    }
    
    class _MyStatefulAppState extends State<MyStatefulApp> {
      GlobalKey _smallTextKey = GlobalKey();
      double _bigTextMarginTop = 0;
    
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
      }
    
      _afterLayout(_) {
        _getSizes();
      }
    
      _getSizes() {
        final RenderBox renderBoxRed =
            _smallTextKey.currentContext.findRenderObject();
        final smallTextSize = renderBoxRed.size;
        setState(() {
          _bigTextMarginTop = smallTextSize.height;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        print('Margin = $_bigTextMarginTop');
        return MaterialApp(
          title: 'Flutter',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(
            body: Center(
                child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: <Widget>[
                SizedBox(
                  height: _bigTextMarginTop,
                ),
                Text(
                  'Hello',
                  style: TextStyle(
                      fontSize: 120,
                      backgroundColor: Colors.red,
                      color: Colors.white),
                ),
                Text(
                  'Hello',
                  style: TextStyle(
                      fontSize: 40,
                      backgroundColor: Colors.green,
                      color: Colors.white),
                  key: _smallTextKey,
                ),
              ],
            )),
          ),
        );
      }
    }
    

    enter image description here

    Hope it help!