利用AnimationController来控制导航栏高度以及cancel按钮的宽度即可
把导航栏和搜索栏封成一个组件,暴露输入回调和搜索回调,方便使用
SearchAppBar组件完整代码:
import 'package:flutter/material.dart';
import 'package:supervision/common/utils/utils.dart';
class SearchAppBar extends StatefulWidget {
final Function(String)? onChange;
final Function(String)? onSearch;
const SearchAppBar({Key? key, this.onChange, this.onSearch}) : super(key: key);
@override
State<SearchAppBar> createState() => _SearchAppBarState();
}
class _SearchAppBarState extends State<SearchAppBar>
with TickerProviderStateMixin {
AnimationController? animationController;
Animation<double>? animation;
final TextEditingController searchController = TextEditingController();
// 是否隐藏清除按钮
bool hideClearBtn = true;
@override
void initState() {
super.initState();
animationController = AnimationController(
duration: const Duration(milliseconds: 100), vsync: this);
animation = Tween(begin: 1.0, end: 0.0).animate(animationController!);
}
@override
void dispose() {
animationController?.dispose();
searchController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: [
_appBar(),
_searchBar(),
],
),
);
}
Widget _appBar() {
return SizeTransition(
sizeFactor: animation!,
axis: Axis.vertical,
child: Container(
height: 64,
decoration: const BoxDecoration(
border:
Border(bottom: BorderSide(width: 1, color: Color(0xffefefef))),
),
alignment: Alignment.center,
child: const Text(
'搜索',
style: TextStyle(
fontSize: 16,
),
),
),
);
}
Widget _searchBar() {
return AnimatedBuilder(
animation: animation!,
builder: (context, child) {
return Row(
children: [
Expanded(
child: Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: const Color(0xffefefef),
),
height: 45,
child: TextField(
controller: searchController,
cursorColor: Colors.blueAccent,
style: const TextStyle(
fontSize: 14,
),
decoration: InputDecoration(
hintText: '请输入搜索内容',
prefixIcon: const Padding(
padding: EdgeInsets.only(left: 10, right: 5),
child: Icon(
Icons.search,
size: 20,
color: Colors.grey,
),
),
prefixIconConstraints: const BoxConstraints(),
suffixIcon: Offstage(
offstage: hideClearBtn,
child: IconButton(
icon: const Icon(Icons.clear, color: Colors.grey),
iconSize: 16,
onPressed: () {
searchController.clear();
setState(() {
hideClearBtn = true;
});
},
),
),
contentPadding: const EdgeInsets.only(left: 12),
),
textInputAction: TextInputAction.search,
onTap: () {
animationController?.forward();
},
onChanged: (value) {
setState(() {
hideClearBtn = value.isEmpty;
});
if (widget.onChange != null) {
widget.onChange!(value);
}
},
onSubmitted: (value) {
if (widget.onSearch != null) {
widget.onSearch!(value);
}
},
),
),
),
GestureDetector(
onTap: () {
Utils.dismissKeyboard(context);
animationController?.reverse();
},
child: Container(
padding: const EdgeInsets.only(right: 10),
color: Colors.transparent,
width: 70 * (1 - animation!.value),
height: 45,
alignment: Alignment.center,
child: const Text(
'Cancel',
style: TextStyle(
fontSize: 14,
),
),
),
),
],
);
},
);
}
}
使用:
SearchAppBar(
onChange: (value) {
print('onChange: $value');
},
onSearch: (value) {
print('onSearch: $value');
},
)
网友评论