Filling the space vertically is not as straight forward and not a default behaviour as it is for the horizontal part. It's because you usually don't want that behaviour: most of the time you want the content itself to determine the space vertically and make a view scrollable if it's too much content (and therefore not enough space available). There are also cases for horizontally scrollable elements, but thats special behaviour then.
If you insist on forcing to fill the space vertically, you need to do that manually. In this case, you have to determine the available space and set the heights of your elements. Best way to determine the available space is making use of the LayoutBuilder widget which gives you that information and updates its subtree if this information changes (since it's a builder widget).
Here you can see a rough and simplified solution using this approach and your example (I enabled the borders so its also visible:
LayoutBuilder(
builder: (context, constraints) => Table(
border: TableBorder.all(),
children: [
TableRow(
children: [
SizedBox(
height: constraints.maxHeight / 2,
child: Align(
child: ElevatedButton(
onPressed: () {},
child: Text('1'),
),
),
),
SizedBox(
height: constraints.maxHeight / 2,
child: Align(
child: ElevatedButton(
onPressed: () {},
child: Text('2'),
),
),
),
],
),
TableRow(
children: [
SizedBox(
height: constraints.maxHeight / 2,
child: Align(
child: ElevatedButton(
onPressed: () {},
child: Text('3'),
),
),
),
SizedBox(
height: constraints.maxHeight / 2,
child: Align(
child: ElevatedButton(
onPressed: () {},
child: Text('4'),
),
),
),
],
),
],
),
),