I want to achieve this:
But when Hero animation starts keyboard is forced to dismiss:
I tried to use widgets callback which is triggered after layout. But this callback is fired whenever hero animation starts. I also tried to use Future.delayed(Duration(seconds: 2), but it does not help. Everything is working as expected if I only remove Hero widget from the widget tree.
Here is my first Screen:
import 'package:flutter/material.dart';
import 'package:move_me_delivery/components/rounded_app_bar.dart';
import 'package:move_me_delivery/components/search_field.dart';
import '../screens.dart';
class HomeTab extends StatelessWidget {
const HomeTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: RoundedAppBar(title: ""),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
children: [
SearchTextField(
onFocusChange: (val) async {
if(val){
await Navigator.push(context, PageRouteBuilder(
transitionDuration: Duration(milliseconds: 400),
pageBuilder: (_, __, ___) => SearchScreen()));
}
},
)
],
),
)
);
}
}
Here is my second screen:
import 'package:flutter/material.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:move_me_delivery/components/search_field.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
@override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
final _focusNode = FocusNode();
@override
void initState() {
super.initState();
_focusNode.requestFocus();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: SafeArea(
child: Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
children: [
SearchTextField(
focus: _focusNode,
onCancel: (){
FocusScope.of(context).unfocus();
Navigator.pop(context);
},
inputDecoration: InputDecoration(
prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1))
),
),
],
),
),
),
),
);
}
}
And finally here is my SearchField screen with Hero animation:
import 'package:flutter/material.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:move_me_delivery/data/styles.dart';
class SearchTextField extends StatefulWidget {
const SearchTextField({Key? key,
this.onFocusChange,
this.focus,
this.onCancel,
this.inputDecoration
}) : super(key: key);
final void Function(bool hasFocus)? onFocusChange;
final FocusNode? focus;
final VoidCallback? onCancel;
final InputDecoration? inputDecoration;
@override
_SearchTextFieldState createState() => _SearchTextFieldState();
}
class _SearchTextFieldState extends State<SearchTextField>{
late FocusNode _focus;
@override
void initState() {
super.initState();
_focus = widget.focus ?? new FocusNode();
_focus.addListener(
(){
if(widget.onFocusChange != null){
widget.onFocusChange!(_focus.hasFocus);
}
}
);
}
@override
Widget build(BuildContext context) {
return Hero(
tag: "search",
child: Material(
type: MaterialType.card,
child: Row(
children: [
Expanded(
child: TextField(style: AppTextStyles.body2,
focusNode: _focus,
decoration: InputDecoration(
prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
// suffixIcon: Text("Cancel"),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1))
))),
if(widget.onCancel != null)
GestureDetector(
onTap: widget.onCancel,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Cancel"),
),
)
],
),
),
);
}
}

