Flutter for iOS – Side Menu Widget

Code

Ok, time to add the side menu widget to the iPad split view, it should look something like this.

Side menu example.
Side menu example.

We only need one level for now so it is relatively straight forward.

Ta Da

Shows the recipes when the 'Digest' menu item is selected
Shows the recipes when the ‘Digest’ menu item is selected
Shows the content placeholders when the 'Friends' menu item is selected
Shows the content placeholders when the ‘Friends’ menu item is selected

The tricky bit this time was getting the side menu to communicate with the content areas to switch content out based on the the menu item selected.

Next

That’s it for iOS for now.

Before then turning out attention to Android, we will take a look at unit, widget and acceptance tests, see you next time.

XP

Widget Events

The side menu needed to communicate when a menu item was selected so that the content areas could be changed based on the item selected.

To do this I create an event ‘MenuItemtapped’ that is fired when a menu item is tapped and bubbles up to the parent splitview widget, which in turn, sets the selected index value and notifies the content to change.

The event extends the built in widget notification class.

This is powerful stuff and allows us to keep the widgets loosely coupled so that we can use the side menu in another widget other than the splitview should we need to. Chema Rubio article is a good summary on how to use events in your application.

ListTile

Replaced custom list item with the Cupertino version of the ListTile.

Now we have a widget for lists and view model for the list items, that provides a standard list tile experience on iOS that can easily be extend to Android.

Testing Widgets Throw Assertions

Found these useful matchers in the Flutter source code in ‘flutter/dev/conductor/core/test/common.dart’.

Matcher throwsAssertionWith(String messageSubString) {
  return throwsA(
      isA<AssertionError>().having(
          (AssertionError e) => e.toString(),
          'description',
          contains(messageSubString),
      ),
  );
}

Matcher throwsExceptionWith(String messageSubString) {
  return throwsA(
      isA<Exception>().having(
          (Exception e) => e.toString(),
          'description',
          contains(messageSubString),
      ),
  );
}

Usage Example:

expect(
	() => Version.increment(version, level).toString(),
    throwsAssertionWith("Do not increment"),
);

BackBurner

Adding recipes

The functionality to search and add recipes has not been implemented, the priority now is to get everything fully under test and provide a native experience for Android users.

Sub menus

Submenu items with expansion will be added when needed.

Shows and example of submenu items with expansion
Shows and example of submenu items with expansion

List Items

Shows and example of a list item using the CupertinoListTile widget.
Shows and example of a list item using the CupertinoListTile widget.

Not sure if the CupertinoListTile is quite what I want.

  • Text is small.
  • Divider line placement is not centred.
  • Highlighting of selected item could be polished up.

It’s functional for now but list items are very import so we want a great one, so we will revisit it after adding the Android version.

Links

Sound & Vision

Apple TV drama, Suspicion.

One more thing…

“I don’t think it’s good that Apple’s perceived as different. I think it’s important that Apple’s perceived as much better. If being different is essential to doing that, then we have to do that, but if we can be much better without being different, that’d be fine with me. I want to be much better.”

Steve Jobs

Flutter – Split View Widget

Apple recommend using a split view layout on iPads.

Apple's split view layout. (They have resued the term in multitasking)
Apple’s split view layout. (They have resued the term in multitasking)

There is no Cupertino split view component out of the box, so we are going to build this one from scratch.

I used Apple’s Mail application as my benchmark and came up with some requirements:

Three Columns
- Sidebar
- Supplementary (Optional)
- Content

All columns are displayed when in Landscape.

In portrait only the content column is displayed and the nav bar allows you to view the Sidebar and supplementary columns.

The Sidebar has:
- A nav bar with icons
	- Collapse
	- Other actions like edit, del…
- Title (Heading)
- Navigation Tree

The supplementary column has:
- A nav bar with icons
		- Collapse
		- Other actions like edit, del…
- Large Title 
- Sub-title
- Content area, often a list of items

The content column has:
 - A nav bar with icons
	- Other actions like edit, del…
- Large Title
- Content area

Ta Da

Shows a recipe on the iPad in the new splitview.
Shows a recipe on the iPad in the new splitview.
The split view widget tests
The split view widget tests

Next

Spoiler alert: Welcome to the new ‘Next’ section.

The next blog will complete the split view by adding a navigation menu to the sidebar.

This will conclude our work with iOS devices for a while.

Before then turning out attention to Android, we will take a look at unit, widget and acceptance tests, see you next time.

BackBurner

Ran out of time this week to complete the sidebar menu, so it gets it’s own post next time.

The navigation bars in the split view are opaque and do not have the same visual feature of a tab bar that allows the content to scroll under it. The aim is to add this later when we look at more advanced animation techniques.

We are leaving the requirement to only display the content area in portrait mode, with the option to slide in the sidebar and supplementary columns via the navigation bars. It fell into nice to have.

Isolating navigation and httpclient, so that they can be mocked or stubbed in the unit and widget tests, I will pick this up in the testing blog.

XP

85% Reuse

I renamed the ‘screen’ directory to ‘content’ with the aim that all the widgets under it will be used cross platform, and widgets in other directories will be platform specific.

I intend to monitor the code/widgets to see if we can hit or even exceed the expected reuse target across platforms.

Shows expected code resuse of 85% when targeting multiple platforms along side the project widget subdirectories.
Shows expected code resuse of 85% when targeting multiple platforms along side the project widget subdirectories.

More on metrics another time.

Project Structure

The tricky bit is deciding when to put areas under items and when to put items under areas. I start by putting areas under items e.g. the digest folder will have a models folder, a data folder etc… this way the supporting files are located next to the files referencing them.

I will then move things around when I start to feel lost.

Whilst creating the split view widget I moved all widgets models in to the area lib/model directory and all data under lib/data, which is a change in direction, but is working better for me.

Another way to tackle this is to just use the finder in VSCode ?P.

Themes

As part of building this layout, I refactored themes moving them out of the DigestibleMeState file into their own ‘ChangeNotifierProvider’, this has cleaned up the responsibilities and put us in a good position to setup the theme to dynamically change based on the time of day.

Building layouts with Rows and Columns

Split view is the largest piece of UI so far and I personally find it useful to experiment with the layouts using rows, columns and containers with background colours.

It doesn’t take much longer than using a drawing tool to produce a screen design.

I recommend playing with Columns, Rows and Containers when building new UI and just watching what happens.

Working with rows and columns
Working with rows and columns

Sound & Vision

Moments by Jamie Webster

One more thing…

You’ve got to find what you love. And that is as true for your work as it is for your lovers. Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven’t found it yet, keep looking. Don’t settle.”

Steve Jobs_ on finding your passion