Exit
exitIntercepts widget removal, plays the exit animation to completion, then unmounts.
Preview
Installation
Terminal
flutter pub add nib_motionUsage
dart
NibPresence(
children: isVisible
? [
NibMotion(
key: const ValueKey('modal'),
initial: NibAnim(opacity: 0, scale: 0.94),
animate: NibAnim(opacity: 1, scale: 1.0),
exit: NibAnim(opacity: 0, scale: 0.94),
transition: NibTransition.springSnappy,
child: MyModal(),
),
]
: [],
)Examples
Presence Toggle
NibPresence intercepts widget removal so the exit animation plays to completion before unmount.
dart
class PresenceToggleExample extends StatefulWidget {
const PresenceToggleExample({super.key});
@override
State<PresenceToggleExample> createState() => _PresenceToggleExampleState();
}
class _PresenceToggleExampleState extends State<PresenceToggleExample> {
bool _visible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0D1117),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 140,
child: Center(
child: NibPresence(
children: _visible
? [
NibMotion(
key: const ValueKey('card'),
initial: const NibAnim(opacity: 0, scale: 0.9),
animate: const NibAnim(opacity: 1, scale: 1.0),
exit: const NibAnim(opacity: 0, scale: 0.9),
transition: NibTransition.springSnappy,
child: Container(
width: 200,
height: 100,
decoration: BoxDecoration(
color: const Color(0xFF1C2537),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFF54C5F8).withAlpha(50)),
),
child: const Center(
child: Text(
'Toggle Me',
style: TextStyle(
color: Color(0xFFEDF2F7),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
),
]
: [],
),
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: () => setState(() => _visible = !_visible),
style: FilledButton.styleFrom(backgroundColor: const Color(0xFF1C2537)),
child: Text(
_visible ? 'Remove' : 'Show',
style: const TextStyle(color: Color(0xFF54C5F8)),
),
),
],
),
),
);
}
}Slide Exit
Widget slides off-screen on removal. Useful for toasts, drawers, and bottom sheets.
dart
class SlideExitExample extends StatefulWidget {
const SlideExitExample({super.key});
@override
State<SlideExitExample> createState() => _SlideExitExampleState();
}
class _SlideExitExampleState extends State<SlideExitExample> {
bool _visible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0D1117),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 140,
child: Center(
child: NibPresence(
children: _visible
? [
NibMotion(
key: const ValueKey('toast'),
initial: const NibAnim(x: 300, opacity: 0),
animate: const NibAnim(x: 0, opacity: 1),
exit: const NibAnim(x: 300, opacity: 0),
transition: NibTransition.springSnappy,
child: Container(
width: 200,
height: 60,
decoration: BoxDecoration(
color: const Color(0xFF1C2537),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFF54C5F8).withAlpha(50)),
),
child: const Center(
child: Text(
'→ Slide Exit',
style: TextStyle(
color: Color(0xFFEDF2F7),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
),
),
]
: [],
),
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: () => setState(() => _visible = !_visible),
style: FilledButton.styleFrom(backgroundColor: const Color(0xFF1C2537)),
child: Text(
_visible ? 'Dismiss' : 'Show',
style: const TextStyle(color: Color(0xFF54C5F8)),
),
),
],
),
),
);
}
}Scale + Fade Exit
Scales down and fades out on removal — natural for modals and dialogs.
dart
class ScaleExitExample extends StatefulWidget {
const ScaleExitExample({super.key});
@override
State<ScaleExitExample> createState() => _ScaleExitExampleState();
}
class _ScaleExitExampleState extends State<ScaleExitExample> {
bool _visible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF0D1117),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 160,
child: Center(
child: NibPresence(
children: _visible
? [
NibMotion(
key: const ValueKey('modal'),
initial: const NibAnim(opacity: 0, scale: 0.85),
animate: const NibAnim(opacity: 1, scale: 1.0),
exit: const NibAnim(opacity: 0, scale: 0.85),
transition: NibTransition.springGentle,
child: Container(
width: 200,
height: 120,
decoration: BoxDecoration(
color: const Color(0xFF1C2537),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFF54C5F8).withAlpha(50)),
),
child: const Center(
child: Text(
'Scale Exit',
style: TextStyle(
color: Color(0xFFEDF2F7),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
),
]
: [],
),
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: () => setState(() => _visible = !_visible),
style: FilledButton.styleFrom(backgroundColor: const Color(0xFF1C2537)),
child: Text(
_visible ? 'Dismiss' : 'Show',
style: const TextStyle(color: Color(0xFF54C5F8)),
),
),
],
),
),
);
}
}API Reference
API class
NibPresenceAPI Properties
children