Is there a way in Flutter to show user where to click if he click on wrong btn or widget? - animation

I want to show user correct button or other place to click if he clik on wrong thing, like touch ripples effect or other way...
Im new to flutter and i dont know if is possible to have reference to widget and than call some effect on it...
Dont have code for at this time..
So i need "effect" when user click on "wrong" button right button to flash or some animation signal right button.
Thanks.

Use BottonTheme and animationController
when click this button you use another button's AnimationController
code snippet
ButtonTheme(
minWidth: 88.0 *
_animation
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button on top'),
onPressed: () {
_animationController1
.forward();
},
),
)
full code
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: AnimatingButton(),
);
}
}
class AnimatingButton extends StatefulWidget {
#override
AnimatingButtonState createState() {
return new AnimatingButtonState();
}
}
class AnimatingButtonState extends State<AnimatingButton>
with TickerProviderStateMixin {
//Uses a Ticker Mixin for Animations
Animation<double> _animation;
AnimationController _animationController;
Animation<double> _animation1;
AnimationController _animationController1;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(
seconds:
2)); //specify the duration for the animation & include `this` for the vsyc
_animation = Tween<double>(begin: 1.0, end: 2.5).animate(
_animationController); //use Tween animation here, to animate between the values of 1.0 & 2.5.
_animation.addListener(() {
//here, a listener that rebuilds our widget tree when animation.value chnages
setState(() {});
});
_animation.addStatusListener((status) {
//AnimationStatus gives the current status of our animation, we want to go back to its previous state after completing its animation
if (status == AnimationStatus.completed) {
_animationController
.reverse(); //reverse the animation back here if its completed
}
});
_animationController1 = AnimationController(
vsync: this,
duration: Duration(
seconds:
2)); //specify the duration for the animation & include `this` for the vsyc
_animation1 = Tween<double>(begin: 1.0, end: 2.5).animate(
_animationController1); //use Tween animation here, to animate between the values of 1.0 & 2.5.
_animation1.addListener(() {
//here, a listener that rebuilds our widget tree when animation.value chnages
setState(() {});
});
_animation1.addStatusListener((status) {
//AnimationStatus gives the current status of our animation, we want to go back to its previous state after completing its animation
if (status == AnimationStatus.completed) {
_animationController1
.reverse(); //reverse the animation back here if its completed
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animating a Button'),
),
body: Column(
children: <Widget>[
Center(
child: ButtonTheme(
minWidth: 88.0 *
_animation1
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation1
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button below '),
onPressed: () {
_animationController
.forward(); // tapping the button, starts the animation.
},
),
),
),
Center(
child: ButtonTheme(
minWidth: 88.0 *
_animation
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button on top'),
onPressed: () {
_animationController1
.forward();
},
),
),
),
],
),
);
}
}

Related

flutter - bad perf- advice

I'm developing my first app with flutter. At some point I was wondering :Am I developping the UX part correctly ? Meaning am I using the proper widget, is there any better way to do that etc.. I find out about Flutter Performance on Intellj Idea and I saw that most of the pages I developed are red...
FYI : The code I created for a simple page
Flutter inspector result => radio-btn-aligned
import 'package:flutter/material.dart';
import 'package:testapp/my_theme.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: MyAppTheme(ctx: context).defaultTheme,
home: new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: AddDailyTaskPage()),
);
}
}
enum Options { goal, category }
class AddDailyTaskPage extends StatefulWidget {
#override
_AddDailyTaskPageState createState() => new _AddDailyTaskPageState();
}
class _AddDailyTaskPageState extends State<AddDailyTaskPage> {
Options _options = Options.goal;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Container(
child: Text("Task Description"),
),
Container(child: Row(
children: [
Expanded(
child: Row(
children: [
Radio<Options>(
value: Options.goal,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
Text(
'Goal',
style: new TextStyle(fontSize: 16.0),
)
]
)
),
Expanded(
child: Row(
children: [
Container(
child: Radio(
value: Options.category,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
),
Container(
child: Text(
'Category',
style: new TextStyle(
fontSize: 16.0,
),
),
)
],
)
)
],
),)
// Container(
// child: TextField(
// maxLines: 10,
// decoration: InputDecoration(
// // suffixIcon:
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.grey, width: 5.0),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.black, width: 5.0),
// ),
// hintText: 'Description task',
// ),
// ),
// )
],
),
);
}
}
To see the difference, I checked the sample code provided while creating a flutter Project
FYI :
flutter performance result : auto-increment
As we can see on the previous pic, it doesn't seems optimised.. :/
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
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),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Few questions :
1/ Does anyone has / knows a good flutter repo with ton of examples based on performance ?
2/ What is your standard in term of perf ? I mean on my virtual device, the UX seems fluid but if the Flutter Perf is "red", then I'm guessing I'm doing something wrong and there is a better way to do ?
3/ Do you guys knows a website / forum / someone who's willing to do a core review once a week to help me implementing good pattern in my flutter application ?
4/ What is wrong with my current design ? What is wrong with the default design ? Why the performance are doesn't seems good ? I started to read the official documentation for the perf, but how could I know if the UX itself have good perf or not ? Actually by testing some stuff, I find out that putting everything in Container / Row or Column widget, improved a lot the performance but even with this widgets, it's not enough :/
Any advice ?
Thanks for your help
You use a StatefulWidget for the whole page. That means that when you call setState() the whole page gets rebuild.
One example is:
Radio<Options>(
value: Options.goal,
groupValue: _options,
onChanged: (Options value) {
setState(() {
_options = value;
});
},
),
There's no need to rebuild your whole page when you set an option. If you extract that code out into it's own StatefulWidget, only this portion gets rebuild.
You can click on "Track Widget rebuilds" to see what Widgets do rebuild in your app and then think about whether those Widget actually should rebuild.
Once you do smaller Widgets you get the problem that events in one Widget are supposed to influence other Widgets. That's when state management solutions come into play. The weather example of the Bloc package shows a good structure of an app that you can copy.

FadeTransition() widget is animated only once in flutter?

class pin extends StatefulWidget {
#override
_PinState createState() => _PinState();
}
class _PinState extends State<pin> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
bool error = false;
#override
void initState() {
super.initState();
this._controller = AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this);
this._animation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
));
}
#override
Widget build(BuildContext context) {
if(this.error) {
this.error = false;
_controller.forward();
}
return Container(
child: if (this.error)
Container(
child: FadeTransition(
opacity: _animation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset("assets/images/sad_face.png"),
),
],
),
),
),
),
}
}
In the above code FadeTransition() widget is animated when the app is first launched.
and the visibility of FadeTransition() is toggled by the error variable.
but when next time the FadeTransition() widget is visible it is not animated?
what is missing, when toggling FadeTransition() the widget should be animated every time it appears!
the error variable is set from outside using Providers and wherever the error is changed the widget is rebuilt, so no need to use setState()
One thing I noticed is error is always false. There is no code to turn it to true and there are two places where it would be set to false. One of them dependent on if it is true (which it will never be since error = true doesn't exist)
That being said, if you want to make your animation run again, where ever you are toggling this property (usually in a button's onTap method) you have to call setState.
In the setState you can either use
controller.forward(from: 0);
// or
controller.reset(); // stops the animation if in progress
controller.forward();

Flutter - Relative Position Animations

Oops guys, how are you?
I am making an app using flutter and came across an issue related to animations.
Based on my study I wanted to make an animation where a center image on the screen after the animation is on top (topcenter).
But I didn't find a way to animate using relative values (for example the actual screen height value) only with values that I would describe (which causes problems on screens with different sizes).
Does anyone have any solutions?
AnimatedLogo({this.controller}) :
imagePosition = Tween(
begin: (Use screen size here without context),
end: (0 to topcenter)
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(0.0, 0.150),
)
);
You have some options, you can use AnimatedContainer or AnimatedPositioned
All these options can use AlignmentDirectional.bottomCenter , topCenter
For other options, you can reference this https://medium.com/aubergine-solutions/options-to-animate-in-flutter-2cec6612c207
full code with AnimatedContainer
import 'package:flutter/material.dart';
import 'dart:ui';
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(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: Option5()
);
}
}
class Option5 extends StatefulWidget {
#override
_Option5State createState() => _Option5State();
}
class _Option5State extends State<Option5> with TickerProviderStateMixin {
AlignmentDirectional _ironManAlignment = AlignmentDirectional.bottomCenter; //AlignmentDirectional(0.0, 0.7);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/person-96.png'),
fit: BoxFit.cover)),
),
AnimatedContainer(
duration: Duration(seconds: 3),
alignment: _ironManAlignment,
child: Container(
height: 250,
width: 150,
child: Image.asset('assets/images/alarm-80.png'),
),
),
Align(
alignment: AlignmentDirectional.bottomCenter,
child: RaisedButton(
onPressed: () {
_flyIronMan();
},
child: Text('Go'),
color: Colors.red,
textColor: Colors.yellowAccent,
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))),
),
)
],
);
}
void _flyIronMan() {
setState(() {
_ironManAlignment = AlignmentDirectional.topCenter; //AlignmentDirectional(0.0,-0.7);
});
}
}

Flutter low framerate performace

I saw linear degradation of framerate UI when I launch speed_dial animation plugin. The problem appear when I add sharedpref function here:
#override
Widget build(BuildContext context) {
sharedpref_function();
return Scaffold(
to listen a saved value, even If the sharedpref is empty I have this degradation.
After 10min whithout doing nothing before, I measure 1120ms/frame when I call _renderSpeedDial
Here is the full code :
bool _dialVisible = true;
Color _speedDial = Colors.pink;
sharedpref_function() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
}
);
}
_renderSpeedDial() {
return SpeedDial(
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 22.0),
backgroundColor: _speedDial,
// child: Icon(Icons.add),
/* onOpen: () => print('OPENING DIAL'),
onClose: () => print('DIAL CLOSED'),*/
visible: _dialVisible,
curve: Curves.bounceIn,
children: [
SpeedDialChild(
child: Icon(Icons.fullscreen_exit, color: Colors.white),
backgroundColor: Color(0xffa088df),
onTap: () {
setState(() {
});
},
label: '1',
labelStyle: TextStyle(fontWeight: FontWeight.w500,color: Colors.white),
labelBackgroundColor:Color(0xffa088df),
),
],
);
}
#override
Widget build(BuildContext context) {
sharedpref_function(); // here the sharedpref I use to listen saved value
return Scaffold(
body: Stack(
children: <Widget>[
Padding
(
padding: const EdgeInsets.only(right:10.0, bottom:10.0),
child:
_renderSpeedDial(),
),
],
)
);
}
}
Your sharedpref_function() method is being called inside your build method. That's not recommended at all because it will be called on every frame the UI needs to be rebuild and your code, having an animation there, will be called at 60fps (on every frame).
Move your method inside initState or didChangeDependencies (there're even more methods that get called once or a few times like didChangeDependencies).
When you need to update values, you could do it inside an onTap gesture and that's it.
Also, test your app in --release (release mode) to truly test the speed of your app.

Difference between Animation Tween and Animation Controlller

In some Flutter animation tutorials, some uses a Tween and an Animation object. Some uses AnimationController only. Both code below seems to output the same result. So when do we use a Tween with animation and when do we use AnimationController only?
With Tween and animation
import 'dart:core';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_State createState() {
return _State();
}
}
class _State extends State<Test> with TickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;
bool faded = true;
#override
void initState() {
super.initState();
_animationController = new AnimationController(
value:0.0,
vsync: this,
upperBound: 1.0,
lowerBound: 0.0,
duration: new Duration(seconds:1),
);
_animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
elevation: 0.5,
title: new Text(
"Testing views",
style: Theme.of(context).textTheme.title,
),
),
body: _buildBodyAnimationTest(),
// body: _buildTuto(),
);
}
Widget _buildBodyAnimationTest(){
return FadeTransition(
opacity: _animation, //here is the difference
child: InkWell(
onTap: (){
if(faded){
faded = false;
_animationController.reverse();
}else{
faded = true;
_animationController.forward();
}
},
child: new Container(
color: Colors.red,
),
),
);
}
}
Without Tween and Animation
import 'dart:core';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_State createState() {
return _State();
}
}
class _State extends State<Test> with TickerProviderStateMixin {
AnimationController _animationController;
bool faded = true;
#override
void initState() {
super.initState();
_animationController = new AnimationController(
value:0.0,
vsync: this,
upperBound: 1.0,
lowerBound: 0.0,
duration: new Duration(seconds:1),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
elevation: 0.5,
title: new Text(
"Testing views",
style: Theme.of(context).textTheme.title,
),
),
body: _buildBodyAnimationTest(),
// body: _buildTuto(),
);
}
Widget _buildBodyAnimationTest(){
return FadeTransition(
opacity: _animationController, //here is the difference
child: InkWell(
onTap: (){
if(faded){
faded = false;
_animationController.reverse();
}else{
faded = true;
_animationController.forward();
}
},
child: new Container(
color: Colors.red,
),
),
);
}
}
Tweens are objects used to transform the output of an Animation (such as AnimationController).
With AnimationController, you typically have a 0-1 floating value. But you rarely want that.
Tweens allows to map that 0-1 to something more concrete such as red to blue, left to right, ...
Background is my tween sequence color.
Animatable<Color> background = TweenSequence<Color>(
[
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(
begin: colors[_Substance.dayEndBackground],
end: colors[_Substance.dayStartBackground],
),
),
TweenSequenceItem(
weight: 1.0,
tween: ColorTween(
begin: colors[_Substance.dayStartBackground],
end: colors[_Substance.dayEndBackground],
),
),
],
);
This is my controller defined in initState() and updated in every one second:
bgUpdateController = AnimationController(
value: _currentDateTime.hour / 24,
upperBound: 1,
lowerBound: 0,
duration: const Duration(hours: 24),
vsync: this,
)..repeat();
I have used the above background and controller as AnimatedBuilder like below:
AnimatedBuilder(
animation: bgUpdateController,
builder: (context, child) {
return Scaffold(
backgroundColor: background
.chain(
CurveTween(curve: Curves.easeInOutCirc),
)
.evaluate(
AlwaysStoppedAnimation(bgUpdateController.value),
),
...
and the result of my code is:
Conclusion
AnimationController is for how long the animation would be and how to control from time, upper and lower boundary, how to control data with time, length, sequence, etc. while AnimationTween is for the range of animation with time, colour, range, sequence, etc as long the animation would be while.

Resources