Flutter TwoPane widget

This layout has two child panes, which can be shown side-by-side, above-and-below, or a single pane can be prioritized. The relative size of the two pane widgets can be adjusted proportionally, and on dual-screen devices the boundary snaps to the hinge area.

Installing

To make your project depend on dual_screen, the package that contains TwoPane, you can run:

flutter pub add dual_screen

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  dual_screen: ^1.0.2+2

If you added the dependency manually to your pubspec.yaml, you also need to run flutter pub get.

You can now start using the TwoPane widget in your dart files, where you will also need to import the dependency:

import 'package:dual_screen/dual_screen.dart';

Foldable device rendering

When the app is spanned on Surface Duo, each widget fills an entire screen:

Flutter TwoPaneView on Surface Duo, left screen shows a blue widget and the right screen shows an orange widget

Cross-platform rendering

When the app renders on larger screens like a tablet, desktop app, or web page, the panes are shown but their sizing is set proportionally:

Flutter TwoPaneView on desktop, showing two panes side by side, with the first pane taking around a third of the space

TwoPane API

class TwoPane {
  const TwoPane({
    Widget startPane,
    Widget endPane,
    double paneProportion,
    TwoPanePriority panePriority,
    Axis direction,
    TextDirection? textDirection,
    VerticalDirection verticalDirection,
    EdgeInsets padding,
  });
}

Properties of the TwoPane widget:

  • startPane - Start pane, which can sit on the left for left-to-right layouts, or at the top for top-to-bottom layouts. If panePriority is start and there is no hinge, this is the only visible pane.
  • endPane - End pane, which can sit on the right for left-to-right layouts, or at the bottom for top-to-bottom layouts. If panePriority is end, and there is no hinge, this is the only visible pane.
  • paneProportion - Proportion of the screen occupied by the start pane. The end pane takes over the rest of the space. A value of 0.5 will make the two panes equal. This property is ignored for displays with a hinge, in which case each pane takes over one screen.
  • panePriority - Whether to show only one the start pane, end pane, or both. This property is ignored for displays with a hinge, in which case both panes are visible.
  • direction - Whether to stack the two panes vertically or horizontally, similar to Flex direction. This property is ignored for displays with a hinge, in which case the direction is horizontal for vertical hinges and vertical for horizontal hinges.
  • textDirection - When panes are laid out horizontally, this determines which one goes on the left. Behaves the same as Flex textDirection
  • verticalDirection - When panes are laid out vertically, this determines which one goes at the top. Behaves the same as Flex verticalDirection
  • padding - The padding between TwoPane and the edges of the screen. If there is spacing between TwoPane and the root MediaQuery, padding is used to correctly align the two panes to the hinge.

Tip

Most of the parameters provided to TwoPane are ignored when the device has a hinge. This means that you can focus on how the layout works on large screens like tablets and desktops, while also having it adapt well to the dual-screen form factor by default.

Usage example

Widget build(BuildContext context) {
  return TwoPane(
    startPane: BlueA(),
    endPane: OrangeB(),
    paneProportion: 0.3,
    panePriority: MediaQuery.of(context).size.width > 500 ? TwoPanePriority.both : TwoPanePriority.start,
  );
}

This sample code produces the results at the beginning of this article:

  • On Surface Duo, widget A and widget B both take one screen. On the Surface Duo, we notice that the left screen shows a blue widget and the right screen shows an orange widget
  • On a tablet or desktop, widget A takes 30% of the screen while widget B takes the remaining 70%. On desktop, we notice the first, blue pane takes around a third of the space and the second, orange pane takes over the rest
  • On a small phone which is less than 500 logical pixels wide, only widget A is visible. Flutter TwoPaneView on a classic single-screen smartphone. Only the blue pane is visible, as the pane priority conditional gives a different result