skip to Main Content

Is there a simple way to add scrolling to row when there is no room left for space between its items?
I.e. option1 and option2 together in the code above. Trying to apply width constraints to row (or scrollview) in case of option2 didn’t have the necessary effect. Any hints?

import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart' show PointerDeviceKind;

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) =>
    MaterialApp(home: const HomePage(), scrollBehavior: ScrollBehavior(), debugShowCheckedModeBanner: false);
}

class ScrollBehavior extends MaterialScrollBehavior {
  @override
  Set<PointerDeviceKind> get dragDevices => { PointerDeviceKind.touch, PointerDeviceKind.mouse };
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) => LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) =>
    Scaffold(
      appBar: AppBar(title: const Text('scroll test')),
      body: Column(children: [
        // Option1: space between, no scrollable
        _row,
        // Option2: scrollable, no space between
        SingleChildScrollView(scrollDirection: Axis.horizontal, child: _row),
      ]),
    )
  );
}

get _row => Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
  Container(color: Colors.green, child: Text("${'l' * 30}")),
  Container(color: Colors.red,   child: Text("${'r' * 30}")),
]);

2

Answers


  1. You can wrap the Row with LayoutBuilder and make the decision by comparing the available width (by using its constraints value) to the space needed by your Row (follow steps on this answer).

    Login or Signup to reply.
  2. I’ve been using a widget I like to call Expandify for a while now and decided to clean it up and publish it to pub.dev as expandify, which should do what you need. This is fairly cpu-itensive as it requires a separate layout pass so don’t use it willy-nilly wherever.

    What it does is use a LayoutBuilder, a ConstrainedBox, and a IntrinsicHeight widget to first calculate the amount of space available and then make the inner part of the scrollable take up that much space.

    Using it looks like this:

    Expandify(
      direction: Axis.horizontal,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Container(color: Colors.blue, width: 100, height: 100),
          Container(color: Colors.red, width: 100, height: 100),
        ],
      ),
    );
    

    Note that if you don’t specify the mainAxisAlignment, the boxes will just stay at the left side. Also, using one or two in a page shouldn’t cause any issues, but if you have a vertical list with a bunch of rows each doing this you might want to think of re-designing or coming up with a different solution as it could cause performance or cpu issues. Note that there are certain situations where it won’t work, for example inside a scrollable of the same direction.

    The paired down code for Expandify looks like this:

    return LayoutBuilder(builder: (context, viewportConstraints) {
      return SingleChildScrollView(
        child: ConstrainedBox(
          constraints: BoxConstraints(
            minWidth: viewportConstraints.maxWidth,
          ),
          child: IntrinsicHeight(
            child: child,
          ),
        ),
      );
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search