Home > Mobile >  Animate inside a custom search bar in flutter AppBar
Animate inside a custom search bar in flutter AppBar

Time:01-16

I have implemented a custom search bar to be toggled as the user selects it. I'm replacing the SearchBar in the appBar where i need it. Initially the search bar will show an Icon(search) with a String("Search")==> view1 and when click on either of them, it will be replaced with another view which has a searchable textfield ==> view 2. i will post what i did so far. I need to give it a nice animation. The animation should move like this. initiallly the view1 is showing then ==> animate view2 from right to left replacing view1 when need to go back to view1 again then ==> inverse the above animation.

The Workaround so far

class SearchBar extends StatefulWidget with PreferredSizeWidget {
  const SearchBar({Key? key}) : super(key: key);

  @override
  _SearchBarState createState() => _SearchBarState();

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

class _SearchBarState extends State<SearchBar> {
  bool _toggle = true;

  @override
  Widget build(BuildContext context) {
    return AppBar(
      elevation: 0.0,
      backgroundColor: CustomColors.mWhite,
      automaticallyImplyLeading: false,
      title:
          AnimatedContainer(
        width: MediaQuery.of(context).size.width * 0.8,
        decoration: _toggle
            ? null
            : BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(15.0),
                border: Border.all(
                  width: 1,
                  color: CustomColors.grey600,
                ),
              ),
        duration: Duration(seconds: 2),
        child: _toggle
            ? GestureDetector(
                onTap: () {
                  setState(() {
                    _toggle = !_toggle;
                  });
                },
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Icon(
                      Icons.search,
                      size: 24.0,
                    ),
                    SizedBox(
                      width: 10.0,
                    ),
                    Text(
                      "Search",
                      style: tBody1,
                    ),
                  ],
                ),
              )
            : Center(
                child: TextField(
                  textInputAction: TextInputAction.search,
                  decoration: InputDecoration(
                      prefixIcon: IconButton(
                        icon: Icon(Icons.arrow_back_ios),
                        onPressed: () {
                          setState(() {
                            _toggle = !_toggle;
                          });
                        },
                      ),
                      border: InputBorder.none),
                ),
              ),
      ),
      actions: [
        Container(
          width: 50.0,
          height: 50.0,
          padding: EdgeInsets.only(right: 8.0),
          child: Image.asset(
            'assets/images/settings.png',
          ),
        ),
      ],
    );
  }
}

CodePudding user response:

AnimatedContainer should have a width that is depending on the _toggle value, and in your case only the search field should be included in the AnimatedContainer.

I simplified your code a little to show how to get the animation working, see below. The transform parameter is responsible for the right-to-left animation, if you comment it, it will animate from left to right.

I also added an AnimatedOpacity to fade in / out the back icon.

(You can paste the code as it is into DartPad to see how it works.)

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: Scaffold(appBar: SearchBar()));
  }
}

class SearchBar extends StatefulWidget with PreferredSizeWidget {
  const SearchBar({Key? key}) : super(key: key);

  @override
  _SearchBarState createState() => _SearchBarState();

  @override
  Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

class _SearchBarState extends State<SearchBar> {
  bool _toggle = true;

  void _doToggle() => setState(() => _toggle = !_toggle);

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: Stack(children: [
        GestureDetector(
          onTap: _doToggle,
          child: SizedBox(
              height: kToolbarHeight * 0.8,
              child: Row(
                children: const [
                  Icon(
                    Icons.search,
                    size: 24.0,
                  ),
                  SizedBox(
                    width: 10.0,
                  ),
                  Text("Search"),
                ],
              )),
        ),
        AnimatedContainer(
          width: _toggle ? 0 : MediaQuery.of(context).size.width,
          transform: Matrix4.translationValues(_toggle ? MediaQuery.of(context).size.width : 0, 0, 0),
          duration: const Duration(seconds: 1),
          height: kToolbarHeight * 0.8,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(15.0),
            border: Border.all(
              width: 1,
              color: Colors.grey[600]!,
            ),
          ),
          child: TextField(
            textInputAction: TextInputAction.search,
            decoration: InputDecoration(
                prefixIcon: AnimatedOpacity(
                    duration: const Duration(seconds: 1),
                    opacity: _toggle ? 0 : 1,
                    child: IconButton(
                      icon: const Icon(Icons.arrow_back_ios),
                      onPressed: _doToggle,
                    )),
                border: InputBorder.none),
          ),
        )
      ]),
    );
  }
}
  •  Tags:  
  • Related