Animations package provides OpenContainer widget.
This widget has 2 builders: openBuilder closedBuilder.
ClosedBuilder returns the widget that user sees before open and after close widget, in flowing example it is SearchBar.
OpenBuilder returns the page showing after user opens the closed widget, in flowing example it is SearchPage.
open and close actions trigger by calling callback: openContainer, closeContainer.

import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String searchString;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: OpenContainer<String>(
openBuilder: (_, closeContainer) => SearchPage(closeContainer),
onClosed: (res) => setState(() {
searchString = res;
}),
tappable: false,
closedBuilder: (_, openContainer) => SearchBar(
searchString: searchString,
openContainer: openContainer,
),
),
),
),
);
}
}
class SearchBar extends StatelessWidget {
const SearchBar(
{Key key, @required this.searchString, @required this.openContainer})
: super(key: key);
final String searchString;
final VoidCallback openContainer;
@override
Widget build(BuildContext context) {
return Material(
elevation: 3,
borderRadius: BorderRadius.circular(5),
child: InkWell(
onTap: openContainer,
child: Container(
padding: EdgeInsets.all(10),
color: Colors.white,
child: Row(
children: [
Icon(Icons.search),
SizedBox(width: 10),
searchString != null
? Expanded(child: Text(searchString))
: Spacer(),
Icon(Icons.mic),
],
),
),
),
);
}
}
class SearchPage extends StatelessWidget {
const SearchPage(
this.onClose, {
Key key,
}) : super(key: key);
final void Function({String returnValue}) onClose;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
offset: Offset(0, 2),
spreadRadius: 0,
blurRadius: 1,
color: Colors.black26,
)
],
color: Colors.white,
),
child: Row(
children: [
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: onClose,
),
Spacer(),
Icon(Icons.mic),
],
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
OutlineButton(
onPressed: () => onClose(returnValue: 'Flutter'),
child: Text('Search: "Flutter"'),
),
OutlineButton(
onPressed: () => onClose(returnValue: 'Rabbit'),
child: Text('Search: "Rabbit"'),
),
OutlineButton(
onPressed: () => onClose(returnValue: 'What is the Matrix'),
child: Text('Search: "What is the Matrix"'),
),
],
),
),
],
),
),
);
}
}