Home > Enterprise >  Spreading each child of a Column to the top & bottom side
Spreading each child of a Column to the top & bottom side

Time:11-16

I'm trying to go from

enter image description here

to

enter image description here

but I'm not sure how to constraint the top title of the column to its top side and the subtitle to its bottom side. I used an Expanded with the appropriate flex factor in order to make each column (left one and right one) display their data appropriately and constrained their positions using the mainAxis/crossAxis values. How can I do the same for the children of a column though?

Here's the stateful widget that is used for each item in a list:

class PickUpGameItem extends StatefulWidget {
  final String gameId;
  final PickUpGameDetails details;

  const PickUpGameItem(this.gameId, this.details, Key? key) : super(key: key);

  @override
  _PickUpGameItemState createState() => _PickUpGameItemState();
}

class _PickUpGameItemState extends State<PickUpGameItem> {
  PickUpGameDetails? _gameDetails;
  GameDetailsBloc? _detailsBloc;

  @override
  void initState() {
    super.initState();
    _detailsBloc = BlocProvider.of<GameDetailsBloc>(context);
    _detailsBloc!.subscribeToGameDetailsUpdatesWithId(widget.gameId);
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<Tuple2<String, PickUpGameDetails>>(
        stream: _detailsBloc!.detailsUpdatesStream,
        builder: (context, snapshot) {
          if (snapshot.hasError ||
              snapshot.connectionState == ConnectionState.waiting) {
            return const SizedBox();
          } else {
            if (snapshot.data!.item1 == widget.gameId) {
              _gameDetails = snapshot.data!.item2;
            } else {
              _gameDetails = widget.details;
            }
          }
          return Container(
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
            child: Row(
              children: [
                ClipRRect(
                  borderRadius: BorderRadius.circular(10.0),
                  child: _gameDetails!.locationInfo == null
                      ? const SizedBox()
                      : CachedNetworkImage(
                          imageUrl:
                              _gameDetails!.locationInfo!.pictures.elementAt(0),
                          width: 85,
                          height: 85,
                          fit: BoxFit.cover,
                          placeholder: (context, url) => const SizedBox(
                              child: Center(child: CircularProgressIndicator()),
                              width: 10,
                              height: 10),
                        ),
                ),
                const SizedBox(
                  width: 10,
                ),
                Expanded(
                  flex: 7,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        _gameDetails!.locationInfo == null
                            ? 'Loading...'
                            : _gameDetails!.locationInfo!.nam,
                        style: const TextStyle(
                            fontFamily: 'PingFang',
                            fontWeight: FontWeight.w600,
                            fontSize: 15),
                        maxLines: 2,
                        overflow: TextOverflow.ellipsis,
                      ),
                      _gameDetails!.gameData!.hostInfo == null
                          ? Text(
                              _gameDetails!.gameData!.gameTypeMsg!,
                              style: const TextStyle(
                                  color: Colors.black,
                                  fontFamily: 'PingFang',
                                  fontWeight: FontWeight.w200,
                                  fontSize: 16),
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            )
                          : Text(
                              '${_gameDetails!.gameData!.gameTypeMsg!} with ${_gameDetails!.gameData!.hostInfo!.hostNickname}.',
                              style: const TextStyle(
                                  color: Colors.black,
                                  fontFamily: 'PingFang',
                                  fontWeight: FontWeight.w200,
                                  fontSize: 16),
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            ),
                    ],
                  ),
                ),
                Expanded(
                  flex: 3,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(
                        GameData.getGameTimestamp(
                            _gameDetails!.gameData!.dateTime!),
                        style: const TextStyle(
                          color: Colors.black,
                          fontSize: 16,
                          fontFamily: 'PingFang',
                          fontWeight: FontWeight.w500,
                        ),
                      ),
                      const SizedBox(
                        height: 8,
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: [
                          Text(
                            '${_gameDetails!.gameData!.getCurrentPlayerNumber()}/${_gameDetails!.gameData!.maxPlayers}',
                            style: const TextStyle(
                                color: Colors.grey,
                                fontFamily: 'PingFang',
                                fontWeight: FontWeight.w200,
                                fontSize: 16),
                          ),
                          const SizedBox(
                            width: 5,
                          ),
                          const ImageIcon(
                            AssetImage('assets/icons/person.png'),
                            size: 24.0,
                          )
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          );
        });
  }
}

Is there anything that I can improve in this layout in order to make it match the original better?

CodePudding user response:

You can use SizedBox or Spacer.

CodePudding user response:

My first thought was to use a SizedBox() or Spacer() widget to achieve the desired spacing. However, I soon realized that this approach wasn't responsive enough for my case. For example, if the title and subtitle were only 1 line in length at maximum, then they would be too close together and in the middle of the parent row. Similar issues arrised when trying to align the right-most column with the middle one.

I ended up swapping the usage of Column() with Row() widgets in order to make sure that the top parts were aligned and that the bottom parts were aligned as well. Once that was done, I used the Align() widget to constraint the right-most elements to the end of the row. Here is the final result:

@override
  Widget build(BuildContext context) {
    return StreamBuilder<Tuple2<String, PickUpGameDetails>>(
        stream: _detailsBloc!.detailsUpdatesStream,
        builder: (context, snapshot) {
          if (snapshot.hasError ||
              snapshot.connectionState == ConnectionState.waiting) {
            return const SizedBox();
          } else {
            if (snapshot.data!.item1 == widget.gameId) {
              _gameDetails = snapshot.data!.item2;
            } else {
              _gameDetails = widget.details;
            }
          }
          return Container(
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ClipRRect(
                  borderRadius: BorderRadius.circular(10.0),
                  child: _gameDetails!.locationInfo == null
                      ? const SizedBox()
                      : CachedNetworkImage(
                          imageUrl:
                              _gameDetails!.locationInfo!.pictures.elementAt(0),
                          width: 85,
                          height: 85,
                          fit: BoxFit.cover,
                          placeholder: (context, url) => const SizedBox(
                              child: Center(child: CircularProgressIndicator()),
                              width: 10,
                              height: 10),
                        ),
                ),
                const SizedBox(
                  width: 10,
                ),
                Expanded(
                  child: Column(
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.start,
                        mainAxisSize: MainAxisSize.max,
                        children: [
                          Expanded(
                            child: Text(
                              _gameDetails!.locationInfo == null
                                  ? 'Loading...'
                                  : _gameDetails!.locationInfo!.nam,
                              style: const TextStyle(
                                  fontFamily: 'PingFang',
                                  fontWeight: FontWeight.w600,
                                  fontSize: 16),
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                          const SizedBox(
                            width: 5,
                          ),
                          Align(
                            alignment: Alignment.centerRight,
                            child: Text(
                              GameData.getGameTimestamp(
                                  _gameDetails!.gameData!.dateTime!),
                              style: const TextStyle(
                                color: Colors.black,
                                fontSize: 16,
                                fontFamily: 'PingFang',
                                fontWeight: FontWeight.w500,
                              ),
                            ),
                          ),
                        ],
                      ),
                      Row(
                          mainAxisAlignment: MainAxisAlignment.start,
                          mainAxisSize: MainAxisSize.max,
                          children: [
                            _gameDetails!.gameData!.hostInfo == null
                                ? Expanded(
                                    child: Text(
                                      _gameDetails!.gameData!.gameTypeMsg!,
                                      style: const TextStyle(
                                          color: Colors.black,
                                          fontFamily: 'PingFang',
                                          fontWeight: FontWeight.w200,
                                          fontSize: 16),
                                      maxLines: 2,
                                      overflow: TextOverflow.ellipsis,
                                    ),
                                  )
                                : Expanded(
                                    child: Text(
                                      '${_gameDetails!.gameData!.gameTypeMsg!} with ${_gameDetails!.gameData!.hostInfo!.hostNickname}.',
                                      style: const TextStyle(
                                          color: Colors.black,
                                          fontFamily: 'PingFang',
                                          fontWeight: FontWeight.w200,
                                          fontSize: 16),
                                      maxLines: 2,
                                      overflow: TextOverflow.ellipsis,
                                    ),
                                  ),
                            Align(
                              alignment: Alignment.centerRight,
                              child: Text(
                                '${_gameDetails!.gameData!.getCurrentPlayerNumber()}/${_gameDetails!.gameData!.maxPlayers}',
                                style: const TextStyle(
                                    color: Colors.grey,
                                    fontFamily: 'PingFang',
                                    fontWeight: FontWeight.w200,
                                    fontSize: 16),
                              ),
                            ),
                            const SizedBox(
                              width: 5,
                            ),
                            const ImageIcon(
                              AssetImage('assets/icons/person.png'),
                              size: 24.0,
                            )
                          ]),
                    ],
                  ),
                ),
              ],
            ),
          );
        });
  }
  • Related