Row Widget
Row and Column widgets are used when we want to align widgets horizontally and vertically

Let's start with Row widget:
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Row(
          children: <Widget>[
            Container(
              color: Colors.green,
              child: const Text("Child 01"),
            ),
            Container(
              color: Colors.red,
              child: const Text("Child 02"),
            )
          ],
        ),
      ),
    );
  }
}
If you want them to stretch uniformly to occupy the available space, you use the Expanded widget. If you want, let's say, one widget to be like 20% and the other 80%, then the former will be assigned flex: 1 parameter in the Expanded widget and the latter will be assigned flex: 4. By default, both have flex: 1, hence both are same widths.
// ...
children: <Widget>[
  Expanded(
    child: Container(
      color: Colors.green,
      child: const Text("Child 01"),
    ),
  ),
  Expanded(
    child: Container(
      color: Colors.red,
      child: const Text("Child 02"),
    ),
  )
],
// ...
Okay, nice! Now let's take an instance where we have two containers in a row. We've defined the width for the first one. We haven't done so for the second. But due to the content of the second widget, there's an overflow on the screen for that particular widget.
// ...
children: <Widget>[
  Container(
    width: MediaQuery.of(context).size.width * 0.7,
    color: Colors.green,
    child: const Text("Child 01"),
  ),
  Container(
    color: Colors.red,
    child: const Text("Child 02 sdfsfsf sefsefe"),
  )
],
// ...
Expanded will most definitely be helpful here on the second widget as it will constrain it to the available remaining space. Also Expanded can be used when the other widgets have defined widths and so you want a particular widget to occupy the remaining available space.
Other options which I've talked about in the next lessons are SingleChildScrollView and Wrap
// ...
children: <Widget>[
  Container(
    width: MediaQuery.of(context).size.width * 0.7,
    color: Colors.green,
    child: const Text("Child 01"),
  ),
  Expanded(
    child: Container(
      color: Colors.red,
      child: const Text("Child 02 sdfsfsf sefsefe"),
    ),
  )
],
// ...
Now, let's change our codebase a bit so that we can introduce MainAxisAlignment and CrossAxisAlignment. The MainAxisAlignment deals with aligning child widgets horizontally while the CrossAxisAlignment deals with aligning items on the y-axis.

In the code we'll write, we have to wrap the Row widget in Container with height of screen because by default, a Row widget is only constrained in height to its contents height and no more. If you only need the height and width attributes, instead of Container, use a SizedBox widget

Enum attributes :
MainAxisAlignment ~ start, center, end, spaceEvenly, spaceAround, spaceBetween
CrossAxisAlignment ~ start, center, end, stretch, baseline
// ...
return SafeArea(
  child: Scaffold(
    body: Container(
      height: MediaQuery.of(context).size.height,
      decoration:
          BoxDecoration(border: Border.all(color: Colors.red, width: 5.0)),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Container(
            color: Colors.green,
            child: const Text("Child 01"),
          ),
          Container(
            color: Colors.red,
            child: const Text("Child 02"),
          )
        ],
      ),
    ),
  ),
);
// ...