
Adding animations to Flutter apps is essential these days, because the
competition of creating stunning beautiful UIs is so high. And if your app
doesn't include at least one animation, you are probably doing something
wrong.
So in this Flutter example, I'm gonna show you how to use AnimatedContainer to
create an animated search bar. It's so easy, that you don't need
AnimationController, AnimatedBuilder...etc.
What's AnimatedContainer?
It's the similar version of the Container widget, but it's animated, which
means it can gradually changes its values over a period of time.
It's important to note that its child and descendants are not animated.
It's used to create
implicit animations, which is good for
simple transitions
(e.g switching between two states for a widget).
How to trigger the animation in AnimatedContainer?
You can do that by using setState(), StreamBuilder or any other mechanism
that can alter the values of the AnimatedContainer parameters.
Let's begin...
I'll start by creating a private boolean called '_folded', which is gonna be
used to alter the values of the AnimatedContainer's parameters, by calling
setState().
bool _folded = true;
Now, I'm gonna create the AnimatedContainer with duration of 400
milliseconds, adding borderRadius and boxShadow. Keep your eye on the width
property, because in it I've used the ternary operator to alter its value.
AnimatedContainer(
duration: Duration(milliseconds: 400),
width: _folded ? 56 : 200,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: Colors.white,
boxShadow: kElevationToShadow[6],
),
Did you notice how in the boxShadow property that I haven't created
boxShadows from scratch. All I've did was using the built-in boxshadows from
the
kElevationToShadow
map.
The child of the AnimatedContainer is a Row widget, which its first child is
an Expanded widget for the TextField widget. Mind the ternary operator.
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 16),
child: !_folded
? TextField(
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Colors.blue[300]),
border: InputBorder.none),
)
: null,
),
),
The second child of the Row is a Container, which has the close/search icon.
I've set the borderRadius of the InkWell to be the same as the first parent
(AnimatedContainer), so when the user taps on it the splash would be
rounded.
Container(
child: Material(
type: MaterialType.transparency,
child: InkWell(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(_folded ? 32 : 0),
topRight: Radius.circular(32),
bottomLeft: Radius.circular(_folded ? 32 : 0),
bottomRight: Radius.circular(32),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
_folded ? Icons.search : Icons.close,
color: Colors.blue[900],
),
),
onTap: () {
setState(() {
_folded = !_folded;
});
},
),
),
),
The important thing to say about the preivous code snippet is:
The use of InkWell with Material widget
Here's a Flutter fact: If one of the ancestors of the InkWell widget is a
Container (or AnimatedContainer) with its color property set, tapping on
that InkWell would not show a splash, because it's drawn under the color
layer of the Container. The solution is one of two ways:
- Change that Container to be an Ink widget. Keep all its parameters, just change the word 'Container' before the opening parenthesis '(' to 'Ink'. Watch out if one of the parameters isn't found in the Ink.
- Wrap that InkWell with a Material widget and set its type to be 'MaterialType.transparency'.
At the end, I just wanna say that this is just my way of the creating that
widget, you may write an entire different code with the same visual
appearnce, so we are all good.
The Full Code
import 'package:flutter/material.dart';
class AnimatedSearchBar extends StatefulWidget {
@override
_AnimatedSearchBarState createState() => _AnimatedSearchBarState();
}
class _AnimatedSearchBarState extends State<AnimatedSearchBar> {
bool _folded = true;
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 400),
width: _folded ? 56 : 200,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: Colors.white,
boxShadow: kElevationToShadow[6],
),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 16),
child: !_folded
? TextField(
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Colors.blue[300]),
border: InputBorder.none),
)
: null,
),
),
Container(
child: Material(
type: MaterialType.transparency,
child: InkWell(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(_folded ? 32 : 0),
topRight: Radius.circular(32),
bottomLeft: Radius.circular(_folded ? 32 : 0),
bottomRight: Radius.circular(32),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
_folded ? Icons.search : Icons.close,
color: Colors.blue[900],
),
),
onTap: () {
setState(() {
_folded = !_folded;
});
},
),
),
)
],
),
);
}
}
Hey guys! do you have any questions? I'm here to help.
ReplyDeleteHello, i need to add searchbar widget on top of the listview widgets . I have few lists of image. How can i get a searchbar widget on top of the listview
Deletethank you so much for this
ReplyDeleteWelcome, thanks.
Deletethat's grate thanks, but pleas make video of image loadings animation I mean when you call image it takes sometimes if have some waiting animations will be so grate,thanks
ReplyDelete+1 for your idea, I'll do it.
Deletehow to increase the size of the searchbar??
ReplyDeleteIf you want to increase the width, edit its respective parameter in the AnimatedContainer. And that applies to the height also.
Deletewhat should i do to animate it from left to right instead of right to left. i tried but failed.please help
ReplyDeleteI'm animating from the center of the widget to the both horizontal sides (left & right).
Deletehi. how to animate from right to left. thx
ReplyDeleteGG mohamad TN good luck to you for the next
ReplyDelete