Search code examples
flutterdart

How to align single element of row when the row height is dynamic


I have a row component that has 3 children. The cross axis alignment for the row is set to .start. My usecase is to position the first and last item based on a few conditions. The first Item needs to be always at the top of row CrossAxisAlignment.start and the 3rd item can be either at the .start or at .Center. The main issue here is that the row is placed inside a scrollview and we can't set the height manually. The height needs to be dynamic based on the height/content of the middle child. Now i need to place the last child in the crossAxisAlignment.center but it always stays at the top unless I explicitly set the whole rows CrossAxisAlignment to center.

I've tried using alignment Widget but since the height is not constant at build time it always stays at the top of row.

I've also tried calculating the height using Globalkey, but I need to use PostFrameCallback and setState to make use of that height which is not ideal.

I also tried using IntrinsicHeight widget, but it's computation heavy and rebuilds the widget multiple times, so because of performance reasons i can't use it.

I've also tried a lot of different solutions from here and there and from Ais but none worked for me.

Minimum reproducible code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SingleChildScrollView(
          child: Column(
            children: [
              MyRowWidget(),
            ],
          ),
        ),
      ),
    );
  }
}

class MyRowWidget extends StatelessWidget {
  const MyRowWidget();

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return Container(
          color: Colors.amberAccent,
          constraints: BoxConstraints(maxWidth: constraints.maxWidth),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Icon(Icons.favorite),
              Expanded(
                child: Text(
                  'This is a very long text that should span to multiple lines when exceed' *
                      6,
                  maxLines: null,
                ),
              ),
              Align(
                alignment: Alignment.center,
                child: Icon(Icons.favorite_outline),
              ),
            ],
          ),
        );
      },
    );
  }
}


Solution

  • From your question what I understood is three child in row, first shuld always on top. second can be on top/ center based on the text size and third child should be in center. Let me know if I misunderstood it.

    Hope below sample code can help you

    Output :

    enter image description here

    Source:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: SingleChildScrollView(
              child: Column(
                children: [
                  MyRowWidget(),
                ],
              ),
            ),
          ),
        );
      }
    }
    
    class MyRowWidget extends StatelessWidget {
      const MyRowWidget();
    
      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(
          builder: (context, constraints) {
            return Container(
              color: Colors.amberAccent,
              constraints: BoxConstraints(maxWidth: constraints.maxWidth),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Icon(Icons.favorite),
                  SizedBox(width: 10),
                  Expanded(
                    child: Row(
                      children: [
                        Expanded(
                          child: Text(
                            'This is a very long text that should span to multiple lines when exceed' *
                                10,
                            maxLines: null,
                          ),
                        ),
                        SizedBox(width: 10),
                        Align(
                          alignment: Alignment.center,
                          child: Icon(Icons.favorite_outline),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            );
          },
        );
      }
    }