在 flutter AppBar 中的自定义搜索栏内设置动画
Animate inside a custom search bar in flutter AppBar
我已经实现了一个自定义搜索栏,可以在用户选择它时进行切换。我正在替换我需要的 appBar 中的 SearchBar。
最初,搜索栏将显示一个带有 String("Search")==> view1 的 Icon(search),当单击它们中的任何一个时,它将被另一个具有可搜索文本字段的视图替换 ==> view 2。
我会 post 我到目前为止所做的。
我需要给它一个漂亮的动画。
动画应该像这样移动。
最初显示 view1 然后 ==> 动画 view2 从右到左替换 view1
当需要再次返回 view1 时 ==> 反转上面的动画。
目前的解决方法
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',
),
),
],
);
}
}
AnimatedContainer
应该有一个 width
取决于 _toggle
值,在您的情况下,只有搜索字段应该包含在 AnimatedContainer
中。
我稍微简化了您的代码以展示如何使动画正常工作,请参见下文。 transform
参数负责从右到左动画,如果你注释掉它,它会从左到右动画。
我还添加了一个 AnimatedOpacity
来淡入/淡出后退图标。
(您可以将代码原样粘贴到 DartPad 中以查看其工作原理。)
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),
),
)
]),
);
}
}
我已经实现了一个自定义搜索栏,可以在用户选择它时进行切换。我正在替换我需要的 appBar 中的 SearchBar。 最初,搜索栏将显示一个带有 String("Search")==> view1 的 Icon(search),当单击它们中的任何一个时,它将被另一个具有可搜索文本字段的视图替换 ==> view 2。 我会 post 我到目前为止所做的。 我需要给它一个漂亮的动画。 动画应该像这样移动。 最初显示 view1 然后 ==> 动画 view2 从右到左替换 view1 当需要再次返回 view1 时 ==> 反转上面的动画。
目前的解决方法
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',
),
),
],
);
}
}
AnimatedContainer
应该有一个 width
取决于 _toggle
值,在您的情况下,只有搜索字段应该包含在 AnimatedContainer
中。
我稍微简化了您的代码以展示如何使动画正常工作,请参见下文。 transform
参数负责从右到左动画,如果你注释掉它,它会从左到右动画。
我还添加了一个 AnimatedOpacity
来淡入/淡出后退图标。
(您可以将代码原样粘贴到 DartPad 中以查看其工作原理。)
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),
),
)
]),
);
}
}