I want to switch between 2 card widgets on a button press. I found AnimatedCrossFade which does exactly the same but the switch animation is a fading one. I want to make a flip animation when it switches. How do I do that?
Something like:
...
AnimatedSwitcher(
duration: Duration(milliseconds: 400),
transitionBuilder: (child, animation) => SizeTransition(
sizeFactor: animation.drive(CurveTween(curve:
//these intervals might be wrong, but the point is
//you can differentiate what is transitioning using the key
child.key == Key("flipped")
? Interval(0.5, 1.0)
: Interval(0.0, 0.0)
)),
child: child,
),
child: myState.isButtonFlipped
? FlippedWidget(
key: Key("flipped"),
)
: MyButton(
key: Key("notFlipped"),
),
),
If you want a different transition, look at the source for SizeTransition and see if you can make your own FlipTransition in a similar manner that uses Transform.
Related
I've got a simple AnimatedWidget with one child widget.
AnimatedContainer(
duration: Duration(milliseconds: 2000),
curve: Curves.bounceOut,
decoration: BoxDecoration(
color: Colors.purple,
),
child: FlutterLogo(
size: _boxSize,
),
),
where _boxSize is being animated like so:
void _startAnimation() => setState(() {
_boxSize *= 1.7;
});
AnimatedContainer is not working for child widgets, however. You need to change direct properties of AnimatedContainer for the animation to work.
This is in compliance with documentation:
The [AnimatedContainer] will automatically animate between the old
and new values of properties when they change using the provided curve
and duration. Properties that are null are not animated.
Its child and descendants are not animated.
What is the equivalent of AnimatedContainer which is ALSO ABLE to animate its children?
There are few widgets which will animate the child. You can swap the new flutter logo widget with preferred size using AnimatedSwitcher Widget.
AnimatedSwitcher - This widget will swap the child widget with a new widget.
AnimatedPositioned - It'll change the position of the child from the stack widget whenever the given position changes.
AnimatedAlign - Animated version of align which will change the alignment of the child whenever the given alignment changes.
AnimatedCrossFade - It fades between two children and animate itself between their sizes.
There is no magic widget which would simply recursively animate all children. But I think what you want is an implicitly animated widget. ie. you change the constructor parameters of a widget, and as it changes it animates from one value to the next.
The easiest way is probably the ImplicitlyAnimatedWidget with a AnimatedWidgetBaseState. So for your example to animate a boxSize attribute this could look like:
class AnimatedFlutterLogo extends ImplicitlyAnimatedWidget {
const AnimatedFlutterLogo({Key key, #required this.boxSize, #required Duration duration})
: super(key: key, duration: duration);
final double boxSize;
#override
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState() => _AnimatedFlutterLogoState();
}
class _AnimatedFlutterLogoState extends AnimatedWidgetBaseState<AnimatedFlutterLogo> {
Tween<double> _boxSize;
#override
void forEachTween(visitor) {
_boxSize = visitor(_boxSize, widget.boxSize, (dynamic value) => Tween<double>(begin: value));
}
#override
Widget build(BuildContext context) {
return Container(
child: FlutterLogo(
size: _boxSize?.evaluate(animation),
),
);
}
}
which is imho already pretty concise, the only real boilerplate is basically the forEachTween(visitor) method which has to create Tween objects for all properties you'd like to animate.
I have a card widget which has some info and a button. On button press, I want to animate the card to change to a different card at the same location. The animation will be added later.
As per my current code, I am using a bool to control which widget to display.
My card1 has the following code-
SliverFillRemaining(
child: Padding(
padding: const EdgeInsets.only(
top: 10.0, left: 6.0, right: 6.0, bottom: 6.0),
child: detailsCardIsVisible ? Card(
elevation: 2.0,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: productInfoCard()) : ProductEnquiryWidget()
),
)
The ProductEnquiryWidget is the second card. It has a form with a button. What I want to do is to submit the form on button press and animate back to the first card.
How do I do that? I don't want to put the code for the second card in the same file as the first card as it will make the code too large.
I am using a boolean named detailsCardIsVisible to control which card to display. Is there a way I could manipulate that variable from button tap in the second card?
https://docs.flutter.io/flutter/widgets/AnimatedCrossFade-class.html
AnimatedCrossFade(
duration: const Duration(seconds: 3),
firstChild: FirstChild(),
secondChild: SecondChild(),
crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
)
If you don't want to animate, you can use Visibility:
https://api.flutter.dev/flutter/widgets/Visibility-class.html
It takes a replacement Widget that's displayed when visible is false.
I have some code that creates 7 Raw Material Buttons in the shape of a circle. However I cannot seem to change the size of the circle, or position them closer together.
Page.dart
Row(
children: <Widget>[
new ThemeButton(Colors.red, () => print("red")),
new ThemeButton(Colors.orange, () => print("orange")),
new ThemeButton(Colors.yellow, () => print("yellow")),
new ThemeButton(Colors.green, () => print("green")),
new ThemeButton(Colors.blue, () => print("blue")),
new ThemeButton(Colors.indigo, () => print("pink")),
new ThemeButton(Colors.purple, () => print("purple")),
],
),
ThemeButton.dart
#override
Widget build(BuildContext context) {
return RawMaterialButton (
shape: CircleBorder(),
fillColor: _themeColour,
elevation: 0.0,
highlightElevation: 0.0,
onPressed: () => _onPressed(),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
);
}
Display:
So the three issue I am facing are all around the size and positioning on the element.
The Circles are too small for my liking.
The space around the circles are too wide.
I can click outside the circle and it will still register the click.
I have looked at the arguments for the Raw Material Button and cannot see what I can change. Adding a padding widget and setting it to 0 doesn't help.
Changing the padding property, unfortunately, did not work for me. However, changing the constraints parameter like in this example turned out to be quite effective:
RawMaterialButton(
constraints: BoxConstraints.tight(Size(36, 36)),
onPressed: null,
child: Icon(Icons.trending_up, size: 18),
shape: new CircleBorder(),
elevation: 0.0,
fillColor: Color.fromARGB(255, 240, 240, 240),
),
Hope it helps!
According to the docs for RawMaterialButton, there should be a padding property that you can set in the constructor, which is typical for this type of component. Try updating the padding value in the constructor of the button instead of adding a new Widget. To be clear, trying setting padding to EdgeInsets.all(0.0).
For further sizing, you can start to look at the Row class properties, specifically MainAxisSize, or wrapping them in variations of the Flexible Widget family.
I'm new to Flutter and Dart. Hopes to get some guide on a tutorial exercise I'm stuck.
I'm following Flutter Codelab https://codelabs.developers.google.com/codelabs/flutter/index.html?index=..%2F..index#6 and able to do everything.
There's an exercise it ask us to do that is
Create a fade-in animation effect by wrapping the Container in a FadeTransition widget instead of a SizeTransition.
The code as below
#override
Widget build(BuildContext context) {
return new SizeTransition(
sizeFactor: new CurvedAnimation(
parent: animationController, curve: Curves.easeOut),
axisAlignment: 0.0,
child: new Container(
// ... other codes ...
),
);
}
So I change to FadeTransition, which requires opacity of type Animation<Double>
#override
Widget build(BuildContext context) {
return new FadeTransition(
opacity: animation
child: new Container(
// ... other codes ...
),
);
}
How could I create or send in the animation? (the above code will have animation unrecognizable).
You can try this
opacity: Tween<double>(
begin: 0.0,
end: 1.0,
).animate(animationController),
CurvedAnimation is used for non-linear animation.
See more detail here https://flutter.dev/docs/development/ui/animations/tutorial
Found the answer, by referring to https://proandroiddev.com/getting-your-hands-dirty-with-flutter-basic-animations-6b9f21fa7d17 and modify accordingly.
So to have FadeTransition, basically just replace
opacity: animation
with
opacity: new CurvedAnimation(parent: animationController, curve: Curves.easeIn),
This is not ideal as every time a message is inserted, it is creating a new CurveAnimation, but for the sake of concise solution, I make it so.
I'm using Dismissible to dismiss the items, but when an item is dismissed I get default boring animation. Is there a way to change that animation like Gmail does?
Example:
My own animation (not smooth)
So, in my animation, you can see slight pause when the item is deleted and next item coming up on the screen taking up old item position.
That's the default animation of Dismissible.
List<String> content;
ListView.builder(
itemCount: content.length,
itemBuilder: (context, index) {
return Dismissible(
key: ValueKey(content[index]),
onDismissed: (_) {
setState(() {
content = List.from(content)..removeAt(index);
});
},
background: Container(color: Colors.green),
child: ListTile(
title: Text(content[index]),
),
);
},
)
Thanks to #RĂ©mi Rousselet for his efforts.
Finally I found the reason for that ugly animation. Never use itemExtent when you are planning to use Dismissible. I was mad, I used it.