onTap with Flutter plugin floating_frosted_bottom_bar - flutter

I am using the Flutter plugin floating_frosted_bottom_bar, and I want to display a page when the second item is clicked. I don't know how to do this. The code I have so far is this:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:floating_frosted_bottom_bar/floating_frosted_bottom_bar.dart';
import 'logo_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Frosted bottom bar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Frosted bottom bar'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late int currentPage;
late TabController tabController;
final List<Color> colors = [
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue
];
#override
void initState() {
currentPage = 0;
tabController = TabController(length: 5, vsync: this);
tabController.animation!.addListener(
() {
final value = tabController.animation!.value.round();
if (value != currentPage && mounted) {
changePage(value);
}
},
);
super.initState();
}
void changePage(int newPage) {
setState(() {
currentPage = newPage;
});
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FrostedBottomBar(
opacity: 0.6,
sigmaX: 5,
sigmaY: 5,
child: TabBar(
indicatorPadding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
controller: tabController,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: Colors.blue, width: 4),
insets: EdgeInsets.fromLTRB(16, 0, 16, 8),
),
tabs: [
TabsIcon(
icons: Icons.home,
color: currentPage == 0 ? colors[0] : Colors.white),
TabsIcon(
icons: Icons.search,
color: currentPage == 1 ? colors[1] : Colors.white),
TabsIcon(
icons: Icons.queue_play_next,
color: currentPage == 2 ? colors[2] : Colors.white),
TabsIcon(
icons: Icons.file_download,
color: currentPage == 3 ? colors[3] : Colors.white),
TabsIcon(
icons: Icons.menu,
color: currentPage == 4 ? colors[4] : Colors.white),
],
),
borderRadius: BorderRadius.circular(500),
duration: const Duration(milliseconds: 800),
hideOnScroll: false,
body: (context, controller) => TabBarView(
controller: tabController,
dragStartBehavior: DragStartBehavior.down,
physics: const BouncingScrollPhysics(),
children: colors
.map(
(e) => ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return const Card(child: FittedBox(child: FlutterLogo()));
},
),
)
.toList(),
),
),
);
}
}
class TabsIcon extends StatelessWidget {
final Color color;
final double height;
final double width;
final IconData icons;
const TabsIcon(
{Key? key,
this.color = Colors.white,
this.height = 60,
this.width = 50,
required this.icons})
: super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: height,
width: width,
child: Center(
child: Icon(
icons,
color: color,
),
),
);
}
}
The output I got: https://imgur.com/a/MKkHcEH
I am a beginner in Flutter so if you have a solution, please make it simple. Thanks in advance!

I updated your code, Put your screens in List[Screens] only instead off ffff() , hope it helps.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:floating_frosted_bottom_bar/floating_frosted_bottom_bar.dart';
import 'ffff.dart';
import 'hhkllj.dart';
// import 'logo_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Frosted bottom bar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Frosted bottom bar'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int currentPage = 0;
late TabController tabController;
final List<Color> colors = [
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue
];
List<Widget> Screens = [
fff(),
hhhhh(),
fff(),
hhhhh(),
fff(),
];
#override
void initState() {
tabController = TabController(length: 5, vsync: this);
tabController.animation!.addListener(
() {
final value = tabController.animation!.value.round();
if (value != currentPage && mounted) {
changePage(value);
}
},
);
super.initState();
}
void changePage(int newPage) {
setState(() {
currentPage = newPage;
});
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FrostedBottomBar(
opacity: 0.6,
sigmaX: 5,
sigmaY: 5,
child: TabBar(
indicatorPadding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
controller: tabController,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: Colors.blue, width: 4),
insets: EdgeInsets.fromLTRB(16, 0, 16, 8),
),
tabs: [
TabsIcon(
icons: Icons.home,
color: currentPage == 0 ? colors[0] : Colors.white),
TabsIcon(
icons: Icons.search,
color: currentPage == 1 ? colors[1] : Colors.white),
TabsIcon(
icons: Icons.queue_play_next,
color: currentPage == 2 ? colors[2] : Colors.white),
TabsIcon(
icons: Icons.file_download,
color: currentPage == 3 ? colors[3] : Colors.white),
TabsIcon(
icons: Icons.menu,
color: currentPage == 4 ? colors[4] : Colors.white),
],
),
borderRadius: BorderRadius.circular(500),
duration: const Duration(milliseconds: 800),
hideOnScroll: false,
body: (context, controller) => Screens[currentPage]
// (context, controller) => TabBarView(
// controller: tabController,
// dragStartBehavior: DragStartBehavior.down,
// physics: const BouncingScrollPhysics(),
// children: colors.map(
// (e) => ListView.builder(
// controller: controller,
// itemBuilder: (context, index) {
// return const Card(child: FittedBox(child: FlutterLogo()));
// },
// ),
// )
// .toList(),
// ),
),
);
}
}
class TabsIcon extends StatelessWidget {
final Color color;
final double height;
final double width;
final IconData icons;
const TabsIcon(
{Key? key,
this.color = Colors.white,
this.height = 60,
this.width = 50,
required this.icons})
: super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: height,
width: width,
child: Center(
child: Icon(
icons,
color: color,
),
),
);
}
}

Related

How to use SVG in TabsIcon?

I am making my first Flutter app and I have a question. I have a bottom navigation bar with icons from flutter. But I want to use SVG icons in the bottom navigation bar. How can I do that?
The code I have so far:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int currentPage = 0;
late TabController tabController;
final List<Color> colors = [
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue,
Colors.blue
];
List<Widget> screens = [
InAppWebViewExampleScreen(),
GoogleScreen(),
GoogleScreen(),
YouTubeScreen(),
];
#override
void initState() {
tabController = TabController(length: 5, vsync: this);
tabController.animation!.addListener(
() {
final value = tabController.animation!.value.round();
if (value != currentPage && mounted) {
changePage(value);
}
},
);
super.initState();
}
void changePage(int newPage) {
setState(() {
currentPage = newPage;
});
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FrostedBottomBar(
opacity: 0.6,
sigmaX: 5,
sigmaY: 5,
child: TabBar(
indicatorPadding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
controller: tabController,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: Colors.blue, width: 4),
insets: EdgeInsets.fromLTRB(16, 0, 16, 8),
),
tabs: [
TabsIcon(
icons: Icons.home,
color: currentPage == 0 ? colors[0] : Colors.white),
TabsIcon(
icons: Icons.search,
color: currentPage == 1 ? colors[1] : Colors.white),
TabsIcon(
icons: Icons.queue_play_next,
color: currentPage == 2 ? colors[2] : Colors.white),
TabsIcon(
icons: Icons.file_download,
color: currentPage == 3 ? colors[3] : Colors.white),
TabsIcon(
icons: Icons.menu,
color: currentPage == 4 ? colors[4] : Colors.white),
],
),
borderRadius: BorderRadius.circular(500),
duration: const Duration(milliseconds: 800),
hideOnScroll: false,
body: (context, controller) => screens[currentPage]
),
);
}
}
class TabsIcon extends StatelessWidget {
final Color color;
final double height;
final double width;
final IconData icons;
const TabsIcon(
{Key? key,
this.color = Colors.white,
this.height = 60,
this.width = 50,
required this.icons})
: super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
height: height,
width: width,
child: Center(
child: Icon(
icons,
color: color,
),
),
);
}
}
I am a beginner in Flutter so if you have a solution, please make it simple. Thanks in advance!
I do not think that is possible with BottomNavigationBar, but you have 2 options either making your icon pack and add it to the application and you can reference to this link or using BottomAppBar instead of BottomNavigationBar which allow having a widget child and you can reference to this link.
It's not possible, you can't use it with iconData, you should remove TabsIcon and try to use another widget.

Making a Common Button Widget in Flutter

Im making a common Button widget that have three states Active / Disable / Loading.
im managing the status from the place where I use the ButtonWidget.
I'll post what I did so far.
when I try to run the button widget it gets an error. namely
The following assertion was thrown while finalizing the widget tree:
_ButtonWidgetState#ab5a5(ticker active) was disposed with an active Ticker.
_ButtonWidgetState created a Ticker via its SingleTickerProviderStateMixin, but at the time dispose() was called on the mixin, that Ticker was still active. The Ticker must be disposed before calling super.dispose().
I imagine this is due the to animation I already have in my button widget.
can anyone help me to overcome this.?
would be really helpful.
ButtonWidget
import 'package:flutter/material.dart';
import 'dart:async';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
const TextStyle tButtonMedium = TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
);
enum eButtonType {
bText,
bIcon,
bIconText,
}
enum eButtonState {
bActive,
bDisable,
bLoading,
}
void main() {
runApp(MyApp());
}
class CustomColors {
static const Color grey100 = Color(0xFFF0F0F0);
static const Color grey600 = Color(0xFFAFAFAF);
static const Color mWhite = Color(0xFFFFFFFF);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var _isLoading = false;
eButtonState? btnState;
#override
void initState() {
_makeActive();
super.initState();
}
void _makeActive() {
Future.delayed(
const Duration(seconds: 5),
() => setState(() {
btnState = eButtonState.bActive;
}),
);
}
void _onSubmit() {
setState(() {
btnState = eButtonState.bLoading;
});
Future.delayed(
const Duration(seconds: 10),
() => setState(() {
btnState = eButtonState.bActive;
}));
}
#override
Widget build(BuildContext context) {
return ButtonWidget(
key: UniqueKey(),
onPressed: () {
_onSubmit();
},
btnColor: Colors.white,
borderColor: Colors.blue,
textColor: Colors.blue,
text: "Save",
eButtonState: btnState,
eButtonType: eButtonType.bIconText,
iconData: Icons.save_alt,
);
}
}
////////////////////////////////////////////////////////////////////////
class ButtonWidget extends StatefulWidget {
//
final String? text;
final Color? btnColor;
final Color? borderColor;
final Color? textColor;
final Function? onPressed;
// final bool? isActive;
final eButtonType;
final eButtonState;
final IconData? iconData;
const ButtonWidget({
Key? key,
this.text,
this.btnColor,
this.borderColor,
this.textColor,
this.eButtonType,
this.iconData,
#required this.eButtonState,
#required this.onPressed,
// #required this.isActive,
}) : super(key: key);
#override
_ButtonWidgetState createState() => _ButtonWidgetState();
}
class _ButtonWidgetState extends State<ButtonWidget>
with SingleTickerProviderStateMixin {
late double _scale;
late AnimationController _controller;
#override
void initState() {
_controller = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 100,
),
upperBound: 0.1,
)..addListener(() {
setState(() {});
});
super.initState();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
void buttonHandler() {
_controller.forward();
Timer(const Duration(milliseconds: 50), () {
_controller.reverse();
});
Timer(const Duration(milliseconds: 50), () {
widget.onPressed!();
});
}
#override
Widget build(BuildContext context) {
_scale = 1 - _controller.value;
return Transform.scale(
scale: _scale,
child: ElevatedButton(
style: TextButton.styleFrom(
elevation: widget.eButtonState == eButtonState.bActive ? 2.0 : 0.0,
primary: widget.eButtonState == eButtonState.bActive
? widget.btnColor!
: CustomColors.grey600,
backgroundColor: widget.eButtonState == eButtonState.bActive
? widget.btnColor!
: CustomColors.grey100,
minimumSize: const Size(80.0, 50.0),
maximumSize: const Size(double.infinity, 50.0),
shape: RoundedRectangleBorder(
side: BorderSide(
color: widget.eButtonState == eButtonState.bActive
? widget.borderColor!
: CustomColors.grey100,
width: 2,
),
borderRadius: BorderRadius.circular(16.0),
),
splashFactory: NoSplash.splashFactory,
),
onPressed: () => widget.eButtonState == eButtonState.bActive
? buttonHandler()
: null,
child: widget.eButtonState == eButtonState.bLoading
? const CircularProgressIndicator(
color: CustomColors.grey600,
backgroundColor: Colors.transparent,
)
: (widget.eButtonType == eButtonType.bText
? Text(
widget.text!,
style: tButtonMedium.copyWith(
color: widget.eButtonState == eButtonState.bActive
? widget.textColor!
: CustomColors.grey600,
),
textAlign: TextAlign.center,
textScaleFactor: 1.0,
)
: (widget.eButtonType == eButtonType.bIconText)
? Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
Icon(
widget.iconData,
color: widget.eButtonState == eButtonState.bActive
? widget.textColor
: CustomColors.grey600,
),
Spacer(),
Text(
widget.text!,
style: tButtonMedium.copyWith(
color: widget.eButtonState == eButtonState.bActive
? widget.textColor!
: CustomColors.grey600,
),
textAlign: TextAlign.center,
textScaleFactor: 1.0,
),
Spacer(),
],
)
: Icon(
widget.iconData,
color: widget.eButtonState == eButtonState.bActive
? CustomColors.mWhite
: CustomColors.grey600,
)),
),
);
}
}
I've managed to get to fixed by simply doing
void dispose() {
_controller.dispose();
super.dispose();
}
If anyone wish to have a common button widget. please feel free to use this code. and I appreciate if veterans can guide to improve this widget. cheers

Adding a toggled button/icon to App in flutter

Looking for a way to implement a button that can be toggled back and forth between favorites and history. Is there a way to do this in flutter.
You can try using a custom widget like this one below:
toggle_button.dart
import 'package:flutter/material.dart';
class ToggleButton extends StatefulWidget {
final double width;
final double height;
final String leftDescription;
final String rightDescription;
final Color toggleColor;
final Color toggleBackgroundColor;
final Color toggleBorderColor;
final Color inactiveTextColor;
final Color activeTextColor;
final double _leftToggleAlign = -1;
final double _rightToggleAlign = 1;
final VoidCallback onLeftToggleActive;
final VoidCallback onRightToggleActive;
const ToggleButton(
{Key? key,
required this.width,
required this.height,
required this.toggleBackgroundColor,
required this.toggleBorderColor,
required this.toggleColor,
required this.activeTextColor,
required this.inactiveTextColor,
required this.leftDescription,
required this.rightDescription,
required this.onLeftToggleActive,
required this.onRightToggleActive})
: super(key: key);
#override
_ToggleButtonState createState() => _ToggleButtonState();
}
class _ToggleButtonState extends State<ToggleButton> {
double _toggleXAlign = -1;
late Color _leftDescriptionColor;
late Color _rightDescriptionColor;
#override
void initState() {
super.initState();
_leftDescriptionColor = widget.activeTextColor;
_rightDescriptionColor = widget.inactiveTextColor;
}
#override
Widget build(BuildContext context) {
return Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
color: widget.toggleBackgroundColor,
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
border: Border.all(color: widget.toggleBorderColor),
),
child: Stack(
children: [
AnimatedAlign(
alignment: Alignment(_toggleXAlign, 0),
duration: Duration(milliseconds: 300),
child: Container(
width: widget.width * 0.5,
height: widget.height,
decoration: BoxDecoration(
color: widget.toggleColor,
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
),
),
),
GestureDetector(
onTap: () {
setState(
() {
_toggleXAlign = widget._rightToggleAlign;
_leftDescriptionColor = widget.inactiveTextColor;
_rightDescriptionColor = widget.activeTextColor;
},
);
widget.onRightToggleActive();
},
child: Align(
alignment: Alignment(-1, 0),
child: Container(
width: widget.width * 0.5,
color: Colors.transparent,
alignment: Alignment.center,
child: Text(
widget.leftDescription,
style: TextStyle(
color: _leftDescriptionColor,
fontWeight: FontWeight.bold),
),
),
),
),
GestureDetector(
onTap: () {
setState(
() {
_toggleXAlign = widget._leftToggleAlign;
_leftDescriptionColor = widget.activeTextColor;
_rightDescriptionColor = widget.inactiveTextColor;
},
);
widget.onLeftToggleActive();
},
child: Align(
alignment: Alignment(1, 0),
child: Container(
width: widget.width * 0.5,
color: Colors.transparent,
alignment: Alignment.center,
child: Text(
widget.rightDescription,
style: TextStyle(
color: _rightDescriptionColor,
fontWeight: FontWeight.bold),
),
),
),
),
],
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:stackovfl_70777885/toggle_button.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: EdgeInsets.all(10.0),
child: ToggleButton(
width: 300.0,
height: 60.0,
toggleBackgroundColor: Colors.white,
toggleBorderColor: (Colors.grey[350])!,
toggleColor: (Colors.indigo[900])!,
activeTextColor: Colors.white,
inactiveTextColor: Colors.grey,
leftDescription: 'FAVORITES',
rightDescription: 'HISTORY',
onLeftToggleActive: () {
print('left toggle activated');
},
onRightToggleActive: () {
print('right toggle activated');
},
),
),
);
}
}
This should result in the following:
The onLeftToggleActive(): () {} and onRightToggleActive() {} in main are triggered depending on where the slider moves.

Flutter hero animation between widgets not screens

Hero animation is the best for navigating between screen, but I need same animation between widgets. Like one card moving another place for example: Product Card moves to shoppingcart and something else. Thanks for answers!
Try this one, add_to_cart_animation:
import 'package:add_to_cart_animation/add_to_cart_animation.dart';
import 'package:add_to_cart_animation/add_to_cart_icon.dart';
import 'package:flutter/material.dart';
import 'list_item.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Add To Cart Animation',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Add To Cart Animation'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// We can detech the location of the card by this GlobalKey<CartIconKey>
GlobalKey<CartIconKey> gkCart = GlobalKey<CartIconKey>();
late Function(GlobalKey) runAddToCardAnimation;
var _cartQuantityItems = 0;
#override
Widget build(BuildContext context) {
return AddToCartAnimation(
// To send the library the location of the Cart icon
gkCart: gkCart,
rotation: true,
dragToCardCurve: Curves.easeIn,
dragToCardDuration: const Duration(milliseconds: 1000),
previewCurve: Curves.linearToEaseOut,
previewDuration: const Duration(milliseconds: 500),
previewHeight: 30,
previewWidth: 30,
opacity: 0.85,
initiaJump: false,
receiveCreateAddToCardAnimationMethod: (addToCardAnimationMethod) {
// You can run the animation by addToCardAnimationMethod, just pass trough the the global key of the image as parameter
this.runAddToCardAnimation = addToCardAnimationMethod;
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: false,
actions: [
// Improvement/Suggestion 4.4 -> Adding 'clear-cart-button'
IconButton(
icon: Icon(Icons.cleaning_services),
onPressed: () {
_cartQuantityItems = 0;
gkCart.currentState!.runClearCartAnimation();
},
),
SizedBox(width: 16),
AddToCartIcon(
key: gkCart,
icon: Icon(Icons.shopping_cart),
colorBadge: Colors.red,
),
SizedBox(
width: 16,
)
],
),
body: ListView(
children: [
AppListItem(onClick: listClick, index: 1),
AppListItem(onClick: listClick, index: 2),
AppListItem(onClick: listClick, index: 3),
AppListItem(onClick: listClick, index: 4),
AppListItem(onClick: listClick, index: 5),
AppListItem(onClick: listClick, index: 6),
AppListItem(onClick: listClick, index: 7),
],
),
),
);
}
// Improvement/Suggestion 4.4 -> Running AddTOCartAnimation BEFORE runCArtAnimation
void listClick(GlobalKey gkImageContainer) async {
await runAddToCardAnimation(gkImageContainer);
await gkCart.currentState!.runCartAnimation((++_cartQuantityItems).toString());
}
}
OR
[not null safety]
this is a sample of add to cart, add_cart_parabola:
import 'dart:ui';
import 'package:add_cart_parabola/add_cart_parabola.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
GlobalKey floatKey = GlobalKey();
GlobalKey rootKey = GlobalKey();
Offset floatOffset ;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
RenderBox renderBox = floatKey.currentContext.findRenderObject();
floatOffset = renderBox.localToGlobal(Offset.zero);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
key: rootKey,
width: double.infinity,
height: double.infinity,
color: Colors.grey,
child: ListView(
children: List.generate(40, (index){
return generateItem(index);
}).toList(),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.yellow,
key: floatKey,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget generateItem(int index){
Text text = Text("item $index",style: TextStyle(fontSize:
25),);
Offset temp;
return GestureDetector(
onPanDown: (details){
temp = new Offset(details.globalPosition.dx, details.globalPosition
.dy);
},
onTap: (){
Function callback ;
setState(() {
OverlayEntry entry = OverlayEntry(
builder: (ctx){
return ParabolaAnimateWidget(rootKey,temp,floatOffset,
Icon(Icons.cancel,color: Colors.greenAccent,),callback,);
}
);
callback = (status){
if(status == AnimationStatus.completed){
entry?.remove();
}
};
Overlay.of(rootKey.currentContext).insert(entry);
});
},
child: Container(
color: Colors.orange,
child: text,
),
);
}
}
For animating widget in the same screen you can use AnimatedPositioned widget see the below code
import 'dart:math';
import 'package:flutter/material.dart';
class AnimatedPositionedDemo extends StatefulWidget {
const AnimatedPositionedDemo({Key? key}) : super(key: key);
static String routeName = 'animated_positioned';
#override
_AnimatedPositionedDemoState createState() => _AnimatedPositionedDemoState();
}
class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
late double topPosition;
late double leftPosition;
double generateTopPosition(double top) => Random().nextDouble() * top;
double generateLeftPosition(double left) => Random().nextDouble() * left;
#override
void initState() {
super.initState();
topPosition = generateTopPosition(30);
leftPosition = generateLeftPosition(30);
}
void changePosition(double top, double left) {
setState(() {
topPosition = generateTopPosition(top);
leftPosition = generateLeftPosition(left);
});
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final appBar = AppBar(title: const Text('AnimatedPositioned'));
final topPadding = MediaQuery.of(context).padding.top;
// AnimatedPositioned animates changes to a widget's position within a Stack
return Scaffold(
appBar: appBar,
body: SizedBox(
height: size.height,
width: size.width,
child: Stack(
children: [
AnimatedPositioned(
top: topPosition,
left: leftPosition,
duration: const Duration(seconds: 1),
child: InkWell(
onTap: () => changePosition(
size.height -
(appBar.preferredSize.height + topPadding + 50),
size.width - 150),
child: Container(
alignment: Alignment.center,
width: 150,
height: 50,
child: Text(
'Click Me',
style: TextStyle(
color:
Theme.of(context).buttonTheme.colorScheme!.onPrimary,
),
),
color: Theme.of(context).primaryColor,
),
),
),
],
),
),
);
}
}
I hope it works for you
For Animated widgets, flutter team has provided a video on youtube here
And you can read all about them on their website here

Flutter border change in ListView moves items below

I'm using ListView with simple containers, when you press container in list view it changes selected container width and colour of border, however when this happens it also moves other containers below. What I would like to get is when you select item, change the width and colour of border and don't move items in list as well as items inside of the container.
Please use code below to reproduce the problem, thanks!
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter border demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<int> values = [1, 2, 3];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Border demo'),
centerTitle: true,
),
body: Container(
child: ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) =>
BorderContainer(value: values[index])),
));
}
}
class BorderContainer extends StatefulWidget {
final int value;
const BorderContainer({Key key, this.value}) : super(key: key);
#override
_BorderContainerState createState() => _BorderContainerState();
}
class _BorderContainerState extends State<BorderContainer> {
bool isTapped = false;
#override
Widget build(BuildContext context) {
return Container(
// height: 95, // if we add this rest of list items will not move however it will move items inside of container
child: GestureDetector(
onTapDown: (TapDownDetails details) => setState(() {
isTapped = true;
}),
onTapUp: (TapUpDetails details) => setState(() {
isTapped = false;
}),
child: Container(
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(
width: isTapped ? 2.0 : 1.0,
//when pressing it moves other items because of width change
color:
isTapped ? Colors.grey : Colors.grey.withOpacity(0.3)),
borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Text('${widget.value}'),
Text('Another item in container number: ${widget.value}')
],
),
)),
),
);
}
}
Okay i solved it following way: create extra container with thicker border above container with smaller border and only change colour opacity.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter border demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<int> values = [1, 2, 3];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Border demo'),
centerTitle: true,
),
body: Container(
child: ListView.builder(
itemCount: values.length,
itemBuilder: (BuildContext context, int index) =>
BorderContainer(value: values[index])),
));
}
}
class BorderContainer extends StatefulWidget {
final int value;
const BorderContainer({Key key, this.value}) : super(key: key);
#override
_BorderContainerState createState() => _BorderContainerState();
}
class _BorderContainerState extends State<BorderContainer> {
bool isTapped = false;
#override
Widget build(BuildContext context) {
var innerBorder = Border.all(
width: 1.0,
color: isTapped
? Colors.grey.withOpacity(0)
: Colors.grey.withOpacity(0.3));
var outerBorder = Border.all(
width: 3.0, color: isTapped ? Colors.grey : Colors.grey.withOpacity(0));
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
border: outerBorder, borderRadius: BorderRadius.circular(16)),
child: GestureDetector(
onTapDown: (TapDownDetails details) => setState(() {
isTapped = true;
}),
onTapUp: (TapUpDetails details) => setState(() {
isTapped = false;
}),
child: Container(
decoration: BoxDecoration(
border: innerBorder, borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Text('${widget.value}'),
Text('Another item in container number: ${widget.value}')
],
),
)),
),
),
);
}
}