shawn.blais

Shawn has worked as programmer and product designer for over 20 years, shipping several games on Steam and Playstation and dozens of apps on mobile. He has extensive programming experience with Dart, C#, ActionScript, SQL, PHP and Javascript and a deep proficiency with motion graphics and UX design. Shawn is currently the Technical Director for gskinner.

@tree_fortress

Flutter: Accelerate your testing with Keyboard listeners

Often when working on a new library or widget, you would like to wire up many temporary testing hooks during development.

Usually in Flutter you would create some buttons, and assign some handlers to trigger all the actions you need. The problem with this is the boilerplate and time required to constantly be writing UI. It takes time, and can clutter up your example code substantially, not to mention the on-screen clutter that half a dozen tappable areas introduces.

Coming from a Unity background, (and also Flash), we were accustomed to using keyboard listeners to quickly test things; only building UI when we actually want to see it. It turns out this is quite easy! Just run on one of the desktop targets and use RawKeyboard.instance.addListener and listen for the keys you are interested in.

Lets say you are working on a pageRouter, and you just want to quickly test a variety of links to make sure everything is routing properly. You can just add your listener inside of a StatefulWidget:

  void initState() {
    super.initState();
    RawKeyboard.instance.addListener(_handleKeyDown);
  }

  void _handleKeyDown(RawKeyEvent value) {
      if(kReleaseMode) return; // Don't let these hooks slip into release!
    if (value is RawKeyDownEvent) {
      final k = value.logicalKey;
      if (k == LogicalKeyboardKey.digit1) 
         setState(() => currentPath = "/home");
      if (k == LogicalKeyboardKey.digit2) 
         setState(() => currentPath = "/settings/");
      if (k == LogicalKeyboardKey.digit3) 
         setState(() => currentPath = "/settings/alerts");
      if (k == LogicalKeyboardKey.digit4) 
         setState(() => currentPath = "/settings/profile");
      if (k == LogicalKeyboardKey.digit5) 
         setState(() => currentPath = "/settings/billing");
      ... etc
    }
  }

And you should also clean them up in dispose() otherwise your listener will outlive your view:

@override
  void dispose() {
    RawKeyboard.instance.removeListener(_handleKeyDown);
    super.dispose();
  }

Word of Caution

It’s important to note this is a global key handler, it does not know whether you are typing in a textfield somewhere else, or even if this view is visible/focused. If you do use this for shortcuts in production, you must make sure to handle these edge cases yourself. Generally using a RawKeyboardListener or Shortcuts widget is recommended since they will do this for you.

With that said, there are certainly some cases where you might want an app-wide shortcut, or maybe to trigger shortcuts for Widgets that are not currently focused, and in those cases RawKeyboard is a great option.

Flutter: Creating your own Inherited Widgets

While we generally use Provider or GetIt to pass things around in Flutter, there are times when you don’t want to have any dependencies on these libraries, and instead just want to define your own MyFoo.of(context) lookup. Often this is when you’re creating packages yourself.

There are quite a few deep dives tutorials into this around, but in this post we wanted to keep it extremely short and sweet.

First of all, there are 2 main types of InheritedWidgets you might create, Stateless (some data) or Stateful (some controller). Both are very easy, lets look at Stateless first!

Create a Stateless InheritedWidget

Lets say you have a widget, and you want to allow someone above you in the tree to pass you some simple data. Like maybe your widget relies on a special String that you want to inherit.

Step1) Create an inherited widget that takes the Data you want to inherit:

class MyPathProvider extends InheritedWidget {
  MyPathProvider ({Key? key, required Widget child, required this.path}) : super(key: key, child: child);
  
  final String path;
  Widget build(BuildContext context) => child;

}

Step2) Add .of() and updateShouldNotify() methods to your widget:

static MyPathProvider ? of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<MyPathProvider>();

@override
// rebuild children if .path value changes
bool updateShouldNotify(covariant MyPathProvider oldWidget) => oldWidget.path != path;

Step3) Use the widget in your tree:

return MyUserProvider(path: "some/path", child: ...) 

You’re done! You can now try and look this up using MyUserProvider.of(context).user from any descendants of MyUserProvider.

Create a Stateful InheritedWidget

Step 1) Create a StatefulWidget that takes a child, and declares it’s state as public.

class MyFoo extends StatefulWidget {
  const MyFoo({Key? key, required this.child}) : super(key: key);
  final Widget child;
  @override
  MyFooState createState() => MyFooState();
}

class MyFooState extends State<MyFoo> {
  @override
  Widget build(BuildContext context) => widget.child;
}

Step 2) Create a matching InheritedWidget, with a field for your state.

class _MyInheritedFoo extends InheritedWidget {
  _MyInheritedFoo({Key? key, required Widget child, required this.state}) : super(key: key, child: child);
  final MyFooState state;
  @override
  // Always rebuild children if state changes
  bool updateShouldNotify(covariant InheritedWidget oldWidget) => true;
}

Step 3) Inside your state’s build method, wrap the .child in the InheritedWidget, and pass the state as an argument:

Widget build(BuildContext context) {
    return _MyInheritedFoo(child: widget.child, state: this);
  }

Step 4) Add a single method to your StatefulWidget:

static MyFooState of(BuildContext context) =>
    (context.dependOnInheritedWidgetOfExactType<_MyInheritedFoo>() as _MyInheritedFoo).state;

Step5) Use the widget in your tree return MyFoo(child: …)

You’re done! You can now look up this state from anywhere in the tree, with a simple: MyFooState state = MyFoo.of(context);

You can view the full working example on github. Happy coding 🙂

Flutter: Lazy instantiation with the `late` keyword

With the introduction of NNBD in Dart 2.12, a new keyword was created: late. The primary reason this was created was to allow for non-null fields, that did not have to be immediately initialized.

// Allow this to be null for now, compiler trusts us, that we will assign it.
late final int i; 
MyConstructor(){
   i = getStartIndex(); // Compiler checks at this point, everything is ok!
   i = null; // This will cause an error, compiler is enforcing non-null
}

This was a necessary feature/workaround for Flutter, because of darts requirement to use const initializers, and most Flutter developers are likely familiar with it by now. In this post we’re going to look at some of the other benefits of late!

Continue reading →

Flokk – How we built a Desktop App Using Flutter

Earlier this year Google and Ubuntu approached us with an open brief, to try and create a full-scale desktop application for Linux, macOS, Web, and Windows. The result was Flokk, which we released (and open-sourced) back in July.

In this post, we’re going to dive into some of the challenges we faced, the discoveries we made, and desktop-specific features that we added.

Continue reading →

Flutter Tricks: Widget Size & Position

Occasionally in Flutter, you will need to get the size and/or position of a widget. Some common use cases for this are:

  • You need to measure something and make some decision based on that. For example, you might switch from an expanded column, to a scrolling column, at a certain height threshold.
  • You may want enable or disable a scrollbar based on the height of some content
  • The parent needs to know your position. For example if when you tap a menu button, the parent wants to animate a dot to that position, we need the button to be able to report its position somehow.
Continue reading →

Flutter: Extending State‹T›

Recently we’ve been exploring the ability to extend the base State<T> class, to add additional capabilities to our views, or writing our own custom Mixins to do the same.

Most Developers are familiar with using the various framework Mixins, like TickerProviderStateMixin but what is not commonly known, is how easy it is to create your own flavors of these. Additionally, many developers extend State<T> constantly, and write very repetitive boilerplate code, without realizing how easy it is to create their own BaseState<T> instead.

In this example, we’ll make a “base state” that provides 3 AnimatorControllers to any widget that needs to animate something. We could then apply this to any Widget in our application, and it automatically get 3 animators to play with. No setup, or teardown required.

Continue reading →