stacker 0.1.0 stacker: ^0.1.0 copied to clipboard
A collection of 3 widgets that stack their children, displaying a single child at a time, transitioning between children when a different child is displayed. Stacker can be used modularly as a compone [...]
stacker #
A collection of 3 widgets that stack their children, displaying a single child at a time, transitioning between children when a different child is displayed.
Stacker can be used modularly as a component, to drive single-page apps, or to control multi-step flows within a widget or page.
Usage #
import 'package:stacker/stacker.dart';
StackSwapper #
[StackSwapper] is the simplest of the three widgets. It accepts a single child and implicity transitions to displaying a new child when its child is updated.
/// The child being displayed by the [StackSwapper].
var child = Container(child: Text('A'));
/// Transitions [StackSwapper] to displaying a different widget.
void updateChild() {
child = Container(child: Text('B'));
setState(() {});
}
/// Build the [StackSwapper].
@override
Widget build(BuildContext context) {
return StackSwapper(child);
}
StackSwitcher #
[StackSwitcher] accepts a list of children and the index of the child that should be displayed. When the index is changed it will transition to displaying the child at the new index.
/// The children contained in [StackSwitcher]'s stack.
final children = <Widget>[
Container(child: Text('A')),
Container(child: Text('B')),
Container(child: Text('C')),
Container(child: Text('D')),
Container(child: Text('E')),
];
/// The index of the child in [children] currently being
/// dispalyed by the [StackSwitcher].
var currentChild = 0;
/// Transitions [StackSwitcher] to displaying the next child in the list.
void nextChild() {
currentChild = (currentChild + 1) % children.length;
setState(() {});
}
/// Build the [StackSwitcher].
@override
Widget build(BuildContext context) {
return StackSwitcher(children, child: currentChild);
}
Maintaining States #
The states of every child in the stack can be maintained when they're
not visible by setting the [maintainStates], [maintainAnimations], or
[maintainSizes] parameters to true
.
[maintainStates] will maintain the state of the child.
[maintainAnimations] will keep the animation ticker providers active
while the children are hidden. Setting this to true
will automatically
set [maintainStates] to true
.
[maintainSizes] will maintain the space the hidden children would occupy
if they were visible. Setting this to true
will automatically set
[maintainAnimations] and [maintainStates] to true
.
/// A [StackSwitcher] where every child's state will
/// be maintained when they're hidden.
StackSwitcher(
children,
child: currentChild,
maintainStates: true,
);
An individual child's state/animation/size can be maintained by wrapping the child in a [MaintainState] widget.
[MaintainState] has 2 parameters, [maintainAnimation] and [maintainSize].
Setting [maintainSize] to true
will automatically set [maintainAnimation]
to true
.
/// A list of children whose states will be maintained, or not,
/// independently of one another.
final children = <Widget>[
// The state of this widget will be maintained when it is hidden.
MaintainState(MyStatefulWidget())),
// The state of this child will not be maintained when it is hidden.
MyStatefulWidget(),
// The state and animation tickers of this widget will be
// maintained when it is hidden.
MaintainState(
MyStatefulWidget(),
maintainAnimation: true,
),
// The state of this child will not be maintained when it is hidden.
MyStatefulWidget(),
// The state, animation tickers, and size of this widget will be
// maintained when it is hidden.
MaintainState(
MyStatefulWidget(),
maintainSize: true,
),
];
Stacker #
[Stacker] accepts a single child, which acts as the root of a linear history of widgets, which can be navigated (like a browser's back and forward buttons.)
New children can be built, inserted into, or removed from the stack on the fly.
There a number of direct methods for controlling and navigating the stack, which are accessed from the [Stacker]'s instance.
All of [Stacker]'s navigation/build methods have an optional [onComplete] parameter, which can be used to provide a callback that will be called a single time when the transition triggered by that method completes.
/// An instance of a [Stacker]. By storing the [Stacker] as an instance,
/// its direct methods can be used to control it.
final myStacker = Stacker(MyRootWidget());
/// Builds and transitions to a new [child].
void build(Widget child, {VoidCallback onComplete}) {
myStacker.build(child, onComplete: onComplete);
}
/// Transitions to the child before the child currently being displayed.
void back({VoidCallback onComplete}) {
myStacker.back(onComplete: onComplete);
}
/// Transitions to the child after the child currently being displayed.
void forward({VoidCallback onComplete}) {
myStacker.forward(onComplete: onComplete);
}
/// Transitions to the child at [index].
void open(int index, {VoidCallback onComplete}) {
myStacker.open(index, onComplete: onComplete);
}
/// Transitions to the child before the child currently being displayed,
/// and removing the current child and every child after it from the history.
void pop({VoidCallback onComplete}) {
myStacker.pop(onComplete: onComplete);
}
/// Transitions to the root child.
void root({VoidCallback onComplete}) {
myStacker.root(onComplete: onComplete);
}
Those same methods are also accessible from any of the [Stacker]'s children via a [BuildContext] extension by calling [context] within a [StatelessWidget]'s [build] method, or anywhere within a [State]. Note: These have the same optional parameters as their respective equivalent methods listed above and in the section below.
// Builds and transitions to a new child.
context.stacker.build(child);
// Transitions to the previous child.
context.stacker.back();
// Transitions to the next child.
context.stacker.forward();
// Transitions to the child at [index].
context.stacker.open(index);
// Transitions the previous child and clears the history.
context.stacker.pop();
// Transitions to the root child.
context.stacker.root();
Note: If a [Stacker] is built directly by its parent's [build] method, only its children will be able to access the methods to control the stacker, which may be all you need depending on the use-case.
/// The [Stacker] built here can only be controlled by
/// [MyRootWidget] or any other children added to it.
@override
Widget build(BuildContext context) {
return Stacker(MyRootWidget());
}
Managing the History #
The history can be cleared by calling [clearHistory]. The history is also
cleared when building or appending a widget to the history, unless the [build]
or [append] methods' [clearHistory] parameter is changed to false
, or when
navigating to the root child by setting the [clearHistory] parameter to true
.
/// Builds and transitions to a new [child], clearing the history
/// by default.
///
/// If [clearHistory] is set to `false`, every child in the forward
/// history will be pushed back when the new [child] is built.
void build(Widget child, {bool clearHistory = true}) {
myStacker.build(child, clearHistory: clearHistory);
}
/// Transitions to the root widget in the stack, clearing the history
/// if [clearHistory] is set to `true`.
void root({bool clearHistory = false}) {
myStacker.root(clearHistory: clearHistory);
}
Children can be inserted into or removed from the history by any of the below methods.
/// Inserts a [child] into the stack before the one currently
/// being displayed.
void prepend(Widget child) {
myStacker.prepend(child);
}
/// Inserts a [child] into the stack after the one currently
/// being displayed, clearing the history by default.
void append(Widget child, {bool clearHistory = true}) {
myStacker.append(child, clearHistory: clearHistory);
}
/// Inserts a [child] into the stack at [index], pushing
/// every child occuring on or after [index] back.
void insert(int index, Widget child) {
myStacker.insert(index, child);
}
/// Removes the first instance of [child] from the stack.
void remove(Widget child) {
myStacker.remove(child);
}
/// Removes the child from the stack at [index].
void removeAt(int index) {
myStacker.removeAt(index);
}
/// Removes every widget from stack after the one currently
/// being diplayed, clearing the forward history.
///
/// If [skip] is `> 0`, that number of widgets after the one currently
/// being displayed will be retained in the history.
void clearHistory([int skip = 0]) {
myStacker.clearHistory(skip);
}
All of the above methods are also accessible to a [Stacker]'s children via the [BuildContext] extension. Note: These methods have the same optional parameters as their respective equivalents listed above.
// Inserts a child into the stack before the one currently
// being displayed.
context.stacker.prepend(child);
// Inserts a child into the stack after the one currently
// being displayed, clearing the history by default.
context.stacker.append(child);
// Inserts a [child] into the stack at [index], pushing
// every child occuring on or after [index] back.
context.stacker.insert(index, child);
// Removes the first instance of [child] from the stack.
context.stacker.remove(child);
// Removes the child from the stack at [index].
context.stacker.removeAt(index);
// Removes every widget from stack after the one currently
// being diplayed
context.stacker.clearHistory();
Android Back Button #
The [backButton] parameter can be set to true
to have the [Stacker]
intercept the Android back button and navigate backwards in the [Stacker]'s
history when it's pressed.
/// This [Stacker] can be navigated with Android's back button.
Stacker(
MyRootWidget(),
backButton: true,
);
If the root child is being displayed, the back button will defer to the default behavior.
Maintaining States #
A [Stacker]'s childrens' states can be maintained in the same way as a
[StackSwitcher]s', either by setting the [maintainStates], [maintainAnimations],
or [maintainSizes] parameters to true
, or by wrapping individual children
in a [MaintainState] widget.
Parameters #
Each of the widgets have a number of shared parameters used to provide callbacks or to customize their transition animation.
Transitions #
The transitions between children are handled by a FadeAndTranslate widget, which fades each child in/out while translating their positional offsets.
There are several parameters used to specify the duration, offset, and additional behavior of the transitions.
/// A [StackSwapper] built with the default parameters..
StackSwapper(
myWidget,
// The duration of the transition animation.
transitionDuration: Duration(milliseconds: 240),
// The offset the children translate to during the transition.
transitionTranslation: Offset(0.0, -24.0),
// If `true`, the children will translate in opposite directions,
// if `false`, they'll translate in the same direction.
invertTranslations: true,
// If `true`, the first child built will transition from being hidden
// to being visible, if `false`, it will be built as visible.
transitionFirstChild: false,
),
Note: [StackSwitcher] and [Stacker] have the same default values for their equivalent parameters as the [STackSwapper] above.
Callbacks #
Each of the widgets also accepts two callbacks, [onSwitchStart] and [onSwitchComplete], which are called each time a transition starts and completes, respectively.
Stacker(
myWidget,
// A callback called every time a transition starts.
onSwitchStart: () => print('Transition starting.'),
// A callback called every time a transition has completed.
onSwitchComplete: () => print('Transition completed.'),
);