Solved: Position widgets in Column with different alignments

Question

Asked by P.D.E. on January 07, 2022 (source).

I have the following widget tree:

enter image description here

The ListView has scrollDirection: Axis.horizontal and 2 children. The Column has crossAxisAlignment: CrossAxisAlignment.center with 3 children. The 2nd child is significantly wider than the 1st and 3rd hence it determines the width of the column. How can I make the 1st widget in the column left aligned? Currently all three widgets are centered horizontally as per the crossAxisAlignment of the Column.

Here's the layout of the column:

enter image description here

As expected all three children of the Column get positioned in the center of it. I need to make the first one left aligned.

enter image description here

My code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 2,
              itemBuilder: (BuildContext context, int index) {
                return Padding(
                  padding: const EdgeInsets.only(
                    left: 10,
                    right: 10,
                  ),
                  child: _composeCard(),
                );
              }),
        ),
      ),
    );
  }

  Widget _composeCard() {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 10),
      child: Expanded(
          child: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
          boxShadow: [
            _composeShadow(dy: 2, blur: 8),
            _composeShadow(dy: 0, blur: 1),
          ],
        ),
        child: Material(
          clipBehavior: Clip.antiAlias,
          child: InkWell(
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: const [
                  Text("Header"), // I want to push this widget to the left
                  SizedBox(height: 20),
                  Text("Body: Lorem ipsum dolor sit amet"),
                  SizedBox(height: 20),
                  Text("Footer"),
                ],
              ),
            ),
          ),
        ),
      )),
    );
  }

  BoxShadow _composeShadow({
    required double dy,
    required double blur,
    double spread = 0,
  }) {
    return BoxShadow(
      color: const Color(0xFFDBDBDB),
      offset: Offset(0, dy),
      spreadRadius: spread,
      blurRadius: blur,
    );
  }
}

Thank you!

Answer

Question answered by Helmut S (source).

I modified your code to work. You have to set a width for the item extend in your list, then you can use a row.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 2,
              itemExtent: 300,
              itemBuilder: (BuildContext context, int index) {
                return Padding(
                  padding: const EdgeInsets.only(
                    left: 10,
                    right: 10,
                  ),
                  child: _composeCard(),
                );
              }),
        ),
      ),
    );
  }

  Widget _composeCard() {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 10),
      child: Column(
        children: [
          Expanded(
              child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5.0),
              boxShadow: [
                _composeShadow(dy: 2, blur: 8),
                _composeShadow(dy: 0, blur: 1),
              ],
            ),
            child: Material(
              clipBehavior: Clip.antiAlias,
              child: InkWell(
                child: Padding(
                  padding:
                      const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Row(
                        mainAxisSize: MainAxisSize.max,
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: const [
                          Expanded(
                            child: Text("Header"),
                          ),
                        ],
                      ),
                      const SizedBox(height: 20),
                      const Text("Body: Lorem ipsum dolor sit amet"),
                      const SizedBox(height: 20),
                      const Text("Footer"),
                    ],
                  ),
                ),
              ),
            ),
          )),
        ],
      ),
    );
  }

  BoxShadow _composeShadow({
    required double dy,
    required double blur,
    double spread = 0,
  }) {
    return BoxShadow(
      color: const Color(0xFFDBDBDB),
      offset: Offset(0, dy),
      spreadRadius: spread,
      blurRadius: blur,
    );
  }
}

Edit: I have an alternative solution if you can't use the fixed itemExtend, you could use Stack instead of Column:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(kPaddingPage),
          child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: 2,
              itemBuilder: (BuildContext context, int index) {
                return Padding(
                  padding: const EdgeInsets.only(
                    left: kPaddingItemH,
                    right: kPaddingItemH,
                  ),
                  child: _composeCard(MediaQuery.of(context).size.width),
                );
              }),
        ),
      ),
    );
  }

  Widget _composeCard(double maxWidth) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 10),
      child: Column(
        children: [
          Expanded(
              child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5.0),
              boxShadow: [
                _composeShadow(dy: 2, blur: 8),
                _composeShadow(dy: 0, blur: 1),
              ],
            ),
            child: Material(
              clipBehavior: Clip.antiAlias,
              child: InkWell(
                child: Container(
                  padding:
                      const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
                  child: Stack(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: const [
                          Text("Header"),
                          //other elements
                        ],
                      ),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: const [
                          Text(""),
                          SizedBox(height: 20),
                          Text("Body: Lorem ipsum dolor sit amet"),
                          SizedBox(height: 20),
                          Text("Footer"),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ),
          )),
        ],
      ),
    );
  }

  BoxShadow _composeShadow({
    required double dy,
    required double blur,
    double spread = 0,
  }) {
    return BoxShadow(
      color: const Color(0xFFDBDBDB),
      offset: Offset(0, dy),
      spreadRadius: spread,
      blurRadius: blur,
    );
  }
}

Video Answers on YouTube

FLUTTER FLUTTER-LAYOUT
SHARE: