Press ESC to close

Flutter App : A Flutter package which simplifies navigation flows with a flexible, declarative API

Flow Builder

Flutter Flows made easy!

build
coverage
pub package

Usage

Define a Flow State

The flow state will be the state which drives the flow. Each time this state changes, a new navigation stack will be generated based on the new flow state.

class Profile {
  const Profile({this.name, this.age, this.weight});

  final String? name;
  final int? age;
  final int? weight;

  Profile copyWith({String? name, int? age, int? weight}) {
    return Profile(
      name: name ?? this.name,
      age: age ?? this.age,
      weight: weight ?? this.weight,
    );
  }
}

Create a FlowBuilder

FlowBuilder is a widget which builds a navigation stack in response to changes in the flow state. onGeneratePages will be invoked for each state change and must return the new navigation stack as a list of pages.

FlowBuilder<Profile>( state: const Profile(), onGeneratePages: (profile, pages) { return [ MaterialPage(child: NameForm()), if (profile.name != null) MaterialPage(child: AgeForm()), ]; }, );

Update the Flow State

The state of the flow can be updated via context.flow<T>().update.

class NameForm extends StatefulWidget { @override _NameFormState createState() => _NameFormState(); } class _NameFormState extends State<NameForm> { var _name = ''; void _continuePressed() { context.flow<Profile>().update((profile) => profile.copyWith(name: _name)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Name')), body: Center( child: Column( children: <Widget>[ TextField( onChanged: (value) => setState(() => _name = value), decoration: InputDecoration( labelText: 'Name', hintText: 'John Doe', ), ), RaisedButton( child: const Text('Continue'), onPressed: _name.isNotEmpty ? _continuePressed : null, ) ], ), ), ); } }

Complete the Flow

The flow can be completed via context.flow<T>().complete.

class AgeForm extends StatefulWidget { @override _AgeFormState createState() => _AgeFormState(); } class _AgeFormState extends State<AgeForm> { int? _age; void _continuePressed() { context .flow<Profile>() .complete((profile) => profile.copyWith(age: _age)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Age')), body: Center( child: Column( children: <Widget>[ TextField( onChanged: (value) => setState(() => _age = int.parse(value)), decoration: InputDecoration( labelText: 'Age', hintText: '42', ), keyboardType: TextInputType.number, ), RaisedButton( child: const Text('Continue'), onPressed: _age != null ? _continuePressed : null, ) ], ), ), ); } }

FlowController

A FlowBuilder can also be created with a custom FlowController in cases where the flow can be manipulated outside of the sub-tree.

class MyFlow extends StatefulWidget { @override State<MyFlow> createState() => _MyFlowState(); } class _MyFlowState extends State<MyFlow> { late FlowController<Profile> _controller; @override void initState() { super.initState(); _controller = FlowController(const Profile()); } @override Widget build(BuildContext context) { return FlowBuilder( controller: _controller, onGeneratePages: ..., ); } @override dispose() { _controller.dispose(); super.dispose(); } }

GitHub

https://github.com/felangel/flow_builder

Footer Example