Getting This Error When Trying To Animate An ElevatedButton - flutter

I am currently trying to animate an elevatedButton, nothing too fancy just trying to animate the elevated property. So I’ve scaffolded a new flutter starter app in VS code and added in the relevant code for the animations and animation controller, however I keep getting this error : type ‘double’ is not a subtype of type ‘MaterialStateProperty<double?>?’ I don’t understand why, here’s my code
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> with TickerProviderStateMixin {
AnimationController animationController;
Animation animation;
#override void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
animation = Tween(begin: 50.0, end: 150.0).animate(
CurvedAnimation(
parent: animationController,
curve: Interval(0.0, 1.0, curve: Curves.easeInOut),
),
);
}
#override void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: (){
animationController.forward();
},
child: Text("Button Text"),
style: ButtonStyle(
elevation: animation.value,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

try with this with MaterialStateProperty.all<double>(animation.value), in button style
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> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation animation;
#override void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
animation = Tween(begin: 50.0, end: 150.0).animate(
CurvedAnimation(
parent: animationController,
curve: Interval(0.0, 1.0, curve: Curves.easeInOut),
),
);
}
#override void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: (){
animationController.forward();
},
child: Text("Button Text"),
style: ButtonStyle(
// here you will change the `MaterialStateProperty` value
elevation: MaterialStateProperty.all<double>(animation.value),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

According to ButtonStyle Documentation:
Many of the ButtonStyle properties are MaterialStateProperty objects which resolve to different values depending on the button's state. For example the Color properties are defined with MaterialStateProperty and can resolve to different colors depending on if the button is pressed, hovered, focused, disabled, etc.
So what you need to do is Pass the animation value as a MaterialStateProperty.
In your case it would look like this:
style: ButtonStyle(
elevation: MaterialStateProperty.all(animation.value),
),
Check out the MaterialStateProperty Class documentation to get more info.

Related

How to mimic a natural ball bounce animation in Flutter?

I'm new to flutter animations and want to animate a natural ball bounce in Flutter. I have an image inside a SizedBox within a Transform.translate, when clicked it begins bouncing using the offset, but whenever it gets to the top it reflects backwards (it feels like it collides with an imaginary wall above). I only want it to reflect only when it's at the bottom and when it gets to the top it starts coming back down, as natural as possible.
class MyApp extends StatelessWidget {
const MyApp({super.key});
#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({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _height;
late Animation _curve;
late Animation<Offset> _offset;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_curve = CurvedAnimation(parent: _controller, curve: Curves.linear, reverseCurve: Curves.linear);
_offset = TweenSequence(<TweenSequenceItem<Offset>>[
TweenSequenceItem<Offset>(
tween: Tween<Offset>(begin: const Offset(0, 0), end: const Offset(0, -40)), weight: 50),
]).animate(_curve as Animation<double>);
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (_, __) {
return InkWell(
hoverColor: Colors.transparent,
highlightColor: Colors.transparent,
focusColor: Colors.transparent,
onTap: () => _controller.forward(),
child: Transform.translate(
offset: _offset.value,
child: SizedBox(
// color: Colors.black,
height: 40,
width: 40,
child: Image.asset('lib/ball.png')),
),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Thanks in advance!

how do i move from the first page, to another page by using items from the first page

How do i move from the first page to another page by using items from the first page?
I am using pageview on the page menu, can someone help me?
So basically you can create a variable that contains the value on your first page and while you add your pages in any list you can simply pass that value like
int test=0
final List<Widget> _list = [];
#override
void initState() {
super.initState();
_list.addAll(
const [DashboardScreen(test), WishListScreen(), CartScreen(), ProfileScreen()]);
}
And other side in dashboardscreen
final int test;
const DashboardScreen(this.test, {Key? key}) : super(key: key);
if your page is statful widget then in build file you can simple use widget.test
or if you have stateless widget you can directly use test variable
You can use page controller
// through the page controller you can do using animateToPage or _pageController.jumpToPage(0). here 0 is page index
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: MyPageView(),
);
}
}
class MyPageView extends StatefulWidget {
const MyPageView({Key? key}) : super(key: key);
#override
State<MyPageView> createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
final PageController _pageController = PageController();
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PageView(
controller: _pageController,
children: <Widget>[
Container(
color: Colors.red,
child: Center(
child: ElevatedButton(
onPressed: () {
if (_pageController.hasClients) {
_pageController.animateToPage(
1,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
// you can use animateToPage or _pageController.jumpToPage(0). here 0 is page index
}
},
child: const Text('Next'),
),
),
),
Container(
color: Colors.blue,
child: Center(
child: ElevatedButton(
onPressed: () {
if (_pageController.hasClients) {
_pageController.animateToPage(
0,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
},
child: const Text('Previous'),
),
),
),
],
),
),
);
}
}

Show tooltip once page initialized - Flutter

I need to show a hint/tooltip for the userto indicate the user can get his current location by pressing the button. Have included the Tooltip in the code but only when the user does a long press of the button the tooltip is appearing, i want the tooltip to appear when the screen is initialized.
Code:
GlobalKey _toolTipKey = GlobalKey();
GestureDetector(
onTap: () {
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
},
child: Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: getLocation,
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
)
I recently had to implement the same thing and I after lot of trying I managed to get it working.
You can use stateful widget and call the function to show tooltip in its initState. Now I got the same error as another person.
The method ensureTooltipVisible was called on null.
To solve this, I had to call
await Future.delayed(Duration(milliseconds: 10));
before ensureTooltipVisible() function.
#override
void initState() {
super.initState();
showTooltipIfOnboadingComplete();
}
and the function to show and close tooltip after certain amount of time,
Future showAndCloseTooltip() async {
await Future.delayed(Duration(milliseconds: 10));
tooltipkey.currentState.ensureTooltipVisible();
await Future.delayed(Duration(seconds: 4));
tooltipkey.currentState.deactivate();
}
you will also have to set you Tooltip widget trigger mode as TooltipTriggerMode.manual,
Here is complete code;
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const FloatingSupportButton()
);
}
}
class FloatingSupportButton extends StatefulWidget {
const FloatingSupportButton({Key? key}) : super(key: key);
#override
State<FloatingSupportButton> createState() => _FloatingSupportButtonState();
}
class _FloatingSupportButtonState extends State<FloatingSupportButton> {
// final GlobalKey<TooltipState> tooltipkey = GlobalKey<TooltipState>();
final tooltipkey = GlobalKey<State<Tooltip>>();
#override
void initState() {
super.initState();
showAndCloseTooltip();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Align(
alignment: Alignment.center,
child: Tooltip(
message: "Hello",
triggerMode: TooltipTriggerMode.manual,
key: tooltipkey,
preferBelow: false,
child: FloatingActionButton(
child: const Icon(Icons.add),
shape: const CircleBorder(
side: BorderSide(
color: Colors.white,
),
),
backgroundColor: const Color(0xFFc60c0c),
onPressed: () {
showAndCloseTooltip();
},
),
),
),
);
}
Future showAndCloseTooltip() async {
await Future.delayed(const Duration(milliseconds: 10));
// tooltipkey.currentState.ensureTooltipVisible();
final dynamic tooltip = tooltipkey.currentState;
tooltip?.ensureTooltipVisible();
await Future.delayed(const Duration(seconds: 4));
// tooltipkey.currentState.deactivate();
tooltip?.deactivate();
}
}
Have a great day everyone, hope this was helpful !!
You should use Statefulwidget and in initState write below code
import 'package:flutter/scheduler.dart';
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
Here the Full Source code When you run the app it directly shows "Get current Location" tooltip
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey _toolTipKey = GlobalKey();
#override
void initState() {
super.initState();
SchedulerBinding.instance!.addPostFrameCallback((_) {
// Flutter get callback here when screen initialized.
final dynamic tooltip = _toolTipKey.currentState;
tooltip.ensureTooltipVisible();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Tooltip(
key: _toolTipKey,
message: 'Get current Location',
child: CircleAvatar(
radius: 30,
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
),
],
),
),
);
}
}

Flutter: Spinning sync icon in AppBar

How can I animate an IconButton placed in a AppBar? The sync icon should spinning while a database synchronisation is running.
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dashboard"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.sync), // <-- Icon
onPressed: () {
print("sync");
// start spinning
syncDatabaseFull(); // Returns future and resolves when sync is finish
},
)
],
),
body: Center(
child: RaisedButton(
child: Text('HOME screen'),
onPressed: () {
},
),
),
);
}
}
You can copy paste run full code below
You can extend AnimatedWidget and pass callback
example code below simulate syncDatabaseFull run for 5 seconds
code snippet
class AnimatedSync extends AnimatedWidget {
VoidCallback callback;
AnimatedSync({Key key, Animation<double> animation, this.callback})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Transform.rotate(
angle: animation.value,
child: IconButton(
icon: Icon(Icons.sync), // <-- Icon
onPressed: () => callback()),
);
}
}
actions: <Widget>[
AnimatedSync(
animation: rotateAnimation,
callback: () async{
controller.forward();
await syncDatabaseFull();
controller.stop();
controller.reset();
},
),
],
working demo
full code
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class AnimatedSync extends AnimatedWidget {
VoidCallback callback;
AnimatedSync({Key key, Animation<double> animation, this.callback})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Transform.rotate(
angle: animation.value,
child: IconButton(
icon: Icon(Icons.sync), // <-- Icon
onPressed: () => callback()),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation colorAnimation;
Animation rotateAnimation;
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Future<bool> syncDatabaseFull() async{
await Future.delayed(Duration(seconds: 5), () {
});
return Future.value(true);
}
#override
void initState() {
controller =
AnimationController(vsync: this, duration: Duration(seconds: 200));
rotateAnimation = Tween<double>(begin: 0.0, end: 360.0).animate(controller);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
AnimatedSync(
animation: rotateAnimation,
callback: () async{
controller.forward();
await syncDatabaseFull();
controller.stop();
controller.reset();
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
CustomedSpinningIconButton class
import 'package:flutter/material.dart';
class SpinningIconButton extends AnimatedWidget {
final VoidCallback onPressed;
final IconData iconData;
final AnimationController controller;
SpinningIconButton({Key key, this.controller, this.iconData, this.onPressed})
: super(key: key, listenable: controller);
Widget build(BuildContext context) {
final Animation<double> _animation = CurvedAnimation(
parent: controller,
// Use whatever curve you would like, for more details refer to the Curves class
curve: Curves.linearToEaseOut,
);
return RotationTransition(
turns: _animation,
child: IconButton(
icon: Icon(iconData),
onPressed: onPressed,
),
);
}
}
How to use it:
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1)
);
}
#override
Widget build(BuildContext context) {
...
actions: <Widget>[
SpinningIconButton(
controller: _animationController,
iconData: Icons.sync,
onPressed: () async {
// Play the animation infinitely
_animationController.repeat();
// Sleep 1.5 seconds or await the Async method
print('Something has finished.');
// Complete current cycle of the animation
_animationController.forward(from: _animationController.value);
},
)
],
...
}

How to use 'CupertinoFullscreenDialogTransition'?

I didn't find any example for constructor CupertinoFullscreenDialogTransition
https://api.flutter.dev/flutter/cupertino/CupertinoFullscreenDialogTransition-class.html
I tried to understand below code but I didn't get it.
CupertinoFullscreenDialogTransition({
Key key,
#required Animation<double> animation,
#required this.child,
}) : _positionAnimation = CurvedAnimation(
parent: animation,
curve: Curves.linearToEaseOut,
// The curve must be flipped so that the reverse animation doesn't play
// an ease-in curve, which iOS does not use.
reverseCurve: Curves.linearToEaseOut.flipped,
).drive(_kBottomUpTween),
super(key: key);
Here's a more complete example
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
static const String _title = 'AppBar tutorial';
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.blue[900],
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.white)),
),
title: _title,
home: CupertinoFullscreenDialogTransitionPage(),
);
}
}
//First Page
class CupertinoFullscreenDialogTransitionPage extends StatefulWidget {
#override
_CupertinoFullscreenDialogTransitionState createState() =>
_CupertinoFullscreenDialogTransitionState();
}
class _CupertinoFullscreenDialogTransitionState
extends State<CupertinoFullscreenDialogTransitionPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(60),
child: AppBar(
title: Text("Cupertino Screen Transition"),
centerTitle: true,
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton.filled(
child: Text("Next Page Cupertino Transition"),
onPressed: () => Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
pageBuilder: (context, _, __) {
return FullDialogPage();
},
),
),
),
],
)),
);
}
}
//Second Page
class FullDialogPage extends StatefulWidget {
#override
_FullDialogPageState createState() => _FullDialogPageState();
}
class _FullDialogPageState extends State<FullDialogPage>
with TickerProviderStateMixin {
AnimationController _primary, _secondary;
Animation<double> _animationPrimary, _animationSecondary;
#override
void initState() {
//Primaty
_primary = AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationPrimary = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _primary, curve: Curves.easeOut));
//Secondary
_secondary =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animationSecondary = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _secondary, curve: Curves.easeOut));
_primary.forward();
super.initState();
}
#override
void dispose() {
_primary.dispose();
_secondary.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return CupertinoFullscreenDialogTransition(
primaryRouteAnimation: _animationPrimary,
secondaryRouteAnimation: _animationSecondary,
linearTransition: false,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.indigo[900],
title: Text("Testing"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_primary.reverse();
Future.delayed(Duration(seconds: 1), () {
Navigator.of(context).pop();
});
},
),
),
),
);
}
}
I've made this simple example, I hope it helps you understand how to implement the CupertinoFullscreenDialogTransition Widget.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
AnimationController _animationController;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stackoverflow playground'),
),
body: Container(
child: Column(
children: <Widget>[
CupertinoFullscreenDialogTransition(
primaryRouteAnimation: _animationController,
secondaryRouteAnimation: _animationController,
linearTransition: false,
child: Center(
child: Container(
color: Colors.blueGrey,
width: 300,
height: 300,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
RaisedButton(
onPressed: () => _animationController.forward(),
child: Text('Forward'),
),
RaisedButton(
onPressed: () => _animationController.reverse(),
child: Text('Reverse'),
),
],
),
],
),
)
);
}
}