Animation Flutter Search setState

How to Create Animated Search Bar in Flutter Using AnimatedContainer

Animated Search Bar in Flutter

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.

Animated Search Bar in Flutter Using AnimatedContainer

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'.

Here's three photos to demonstrate what I'm saying:

InkWell with Container widgets

InkWell, Material and Container widgets

InkWell and Ink widgets

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;
                  });
                },
              ),
            ),
          )
        ],
      ),
    );
  }
}

12 comments:

  1. Hey guys! do you have any questions? I'm here to help.

    ReplyDelete
    Replies
    1. Hello, 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

      Delete
  2. that'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
  3. how to increase the size of the searchbar??

    ReplyDelete
    Replies
    1. If you want to increase the width, edit its respective parameter in the AnimatedContainer. And that applies to the height also.

      Delete
  4. what should i do to animate it from left to right instead of right to left. i tried but failed.please help

    ReplyDelete
    Replies
    1. I'm animating from the center of the widget to the both horizontal sides (left & right).

      Delete
  5. hi. how to animate from right to left. thx

    ReplyDelete
  6. GG mohamad TN good luck to you for the next

    ReplyDelete

| Designed by Colorlib