✅ Animate when widget displays on Screen IMMEDIATELY
info
Best Way:
- for animation on Widget build ⏩
TweenAnimationBuilder<double>(..)with child inside build asTransform.translate(..) - for animation on on
↷ back button⏩Beamer+ValueNotifier+ValueListenableBuilder+AnimatedPositioned
Animate on bulding the Widget
✅ TweenAnimationBuilder<double>(..) + Transform.translate(..)
caution
⚠️ NOT shows animation on ↷ back button
TweenAnimationBuilder<double>(..)only makes animation when the Widet is built i.e.TweenAnimationBuilder<double>(..)does NOT show animation on↷ back button
class ShoeDetailsScreen extends StatelessWidget {
Axis _axis = Axis.horizontal; // to check for axis here ,i.e. for different Offset in Transform
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Center(
child: TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 1, end: 0),
duration: const Duration(milliseconds: 1000),
curve: Curves.easeInOutBack,
builder: (context, value, child) {
return Transform.translate(
offset: axis == Axis.horizontal // if `horizontal [x=0]` else `vertical [y=0]`
? Offset(value * 145, 0.0) // Offset(x-axis, y-axis)
: Offset(
0.0,
value * 145, // value is in the builder of Tween...
),
child: Container(
height: 160,
width: 160,
color: Colors.green,
child: const Text('Center'),
),
);
},
),
),
);
}
}
WidgetsBinding.instance.addPostFrameCallback((_) { ... } ),
caution
works ONLY with PositionedFoo.. Widgets
⚠️ NOT shows animation on ↷ back button
TO HAVE ANIMATION ON ↷ back button also we use, Beamer with ValueNotifier as it only shows animation for Back Buttons.
- USE
TweenAnimationBuilder<double>(..)with child inside build asTransform.translate(..)instead of thisTransform..that has more Control thanPositionedFoowidgets
- Also
TweenAnimationBuilderdoes not use ValueNotifier So,TweenAnimationBuilderis MUCH EASIER TO USE
- the widget will be animated from the starting, Applicable ONLY on Implicit Inbuilt Widgets
- when I want the Widget to COME UP from BELOW every time I get to this page
decalring 'WidgetsBinding.instance.addPostFrameCallback((_)'
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) {
valueNotifierBottomButton.value = true;
});
/* ....
*/
using the 'WidgetsBinding.instance.addPostFrameCallback((_)'
class BottomButtons extends StatelessWidget {
final ValueNotifier<bool> valueNotifierBottomButton = ValueNotifier(false); // ✅✅ will be updated at the very start of the creation of the Widget builder
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback( /// ✅✅ MUST always be at the TOP just below the `Widget build(BuildContext context) {`
(_) {
valueNotifierBottomButton.value = true; /// ✅✅ UPDATING the `ValueNotifier<bool>` at the very start of the creation of the Widget builder
},
);
return ValueListenableBuilder<bool>(
valueListenable: valueNotifierBottomButton,
builder: (context, value, child) {
return AnimatedPositioned(
duration: const Duration(milliseconds: 700),
right: 20,
left: 20,
bottom: value ? 25 : 0, // ✅
curve: Curves.easeInOutBack, // ✅
// height: 200,
child: Row(
children: [
FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.favorite_rounded),
),
const Spacer(),
FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.shopping_bag_rounded),
),
],
),
);
},
);
}
}
'BottomButtons' is called here
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:learn_list_view/models/shoes_data.dart';
import '../widgets/bottom_buttons.dart';
class ShoeDetailsScreen extends StatelessWidget {
final ShoesData shoeCardData;
const ShoeDetailsScreen({super.key, required this.shoeCardData});
Widget build(BuildContext context) {
final rnd = Random();
Color getRandomColor() => Color(rnd.nextInt(0xffffffff));
final currentColor = getRandomColor();
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(middle: Text(shoeCardData.name)),
child: Stack(
children: [
const Center(
child: Text('Center'),
),
BottomButtons(),
],
),
);
}
}
<strong>'/shoes/:id'</strong> calling the <strong>ShoeDetailsScreen</strong>
'/shoes/:id': (context, state, data) {
/// my list<ShoeState> is `Iterable` that means I can iterate though it using `firsWhere`
ShoesData currentShoeData = shoesDataList.firstWhere(
(el) => (el.model.toString() ==
(context.currentBeamLocation.state as BeamState)
.pathParameters['id']),
);
return BeamPage(
// instead of `BeamPage(..)`
key: ValueKey(currentShoeData.model),
child: ShoeDetailsScreen(shoeCardData: currentShoeData),
title: currentShoeData.name,
type: BeamPageType.fadeTransition,
// popToNamed: '/nav',
// fullScreenDialog: true,
);
}
/* //
child: InkWell(
onTap: () {
Beamer.of(context).beamToNamed('/shoes/${shoeCardData.model}');
},
borderRadius: BorderRadius.circular(
30), // for the ripple-effect to be inside a particlar border-radius
child: Stack(
children: [
Positioned.fill(
// ....
// ....
.. ........ ..
*/
Animate on back button ↷ back button
✅ using Beamer + ValueNotifier + ValueListenableBuilder + AnimatedPositioned
import 'package:flutter/material.dart';
import 'package:learn_list_view/global/value_notifiers.dart';
class BottomAnimatedNavBar extends StatelessWidget {
const BottomAnimatedNavBar({super.key});
Widget build(BuildContext context) {
print('inside NAV: ${valueNotifierBottomBarVisible.value}');
return ValueListenableBuilder<bool>(
valueListenable: valueNotifierBottomBarVisible,
builder: (context, value, child) {
return AnimatedPositioned(
left: 0,
right: 0,
bottom: value ? 0.0 : -kToolbarHeight,
height: kToolbarHeight, // constant from the Material app
duration: const Duration(milliseconds: 600),
curve: Curves.easeIn,
child: Container(
decoration: const BoxDecoration(color: Colors.white54),
child: Row(
children: [
const Expanded(child: Icon(Icons.home)),
const Expanded(child: Icon(Icons.search_rounded)),
const Expanded(child: Icon(Icons.favorite_rounded)),
const Expanded(child: Icon(Icons.shopping_cart_rounded)),
Expanded(
child: Image.asset('nike_logo.png',
color: Colors.purple, height: 50)),
],
),
),
);
});
}
}