刚起步学习Flutter,还是比较容易上手的。下面介绍一下自定义的带搜索框的AppBar。
项目地址(github)
效果图
image.pngimage.png
1、集成自StatefulWidget,声明属性,注意:这里要实现PreferredSizeWidget,否则不能作为appBar控件引用;
class SearchAppBarWidget extends StatefulWidget implements PreferredSizeWidget {
final double height;
final double elevation; //阴影
final Widget leading;
final String hintText;
final FocusNode focusNode;
final TextEditingController controller;
final IconData prefixIcon;
final List<TextInputFormatter> inputFormatters;
final VoidCallback onEditingComplete;
const SearchAppBarWidget(
{Key key,
this.height: 46.0,
this.elevation: 0.5,
this.leading,
this.hintText: '请输入关键词',
this.focusNode,
this.controller,
this.inputFormatters,
this.onEditingComplete,
this.prefixIcon: Icons.search})
: super(key: key);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new SearchAppBarState();
}
@override
// TODO: implement preferredSize
Size get preferredSize => Size.fromHeight(height);//这里设置控件(appBar)的高度
}
2、SearchAppBarState,这里使用的是PreferredSizeWidget 的实现类PreferredSize,用Stack和Offstage让两个布局(常规的appBar和输入框)重合在一起;
class SearchAppBarState extends State<SearchAppBarWidget> {
bool _hasdeleteIcon = false;
@override
Widget build(BuildContext context) {
// TODO: implement build
return new PreferredSize(
child: new Stack(
children: <Widget>[
new Offstage(
offstage: false,
child:
MoreWidgets.buildAppBar(context, '', leading: widget.leading),
),
new Offstage(
offstage: false,
child: Container(
padding: const EdgeInsets.only(left: 30.0, top: 26.0),
child: new TextField(
focusNode: widget.focusNode,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
controller: widget.controller,
maxLines: 1,
inputFormatters: widget.inputFormatters,
decoration: InputDecoration(
hintText: widget.hintText,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 16.5,
),
prefixIcon: Padding(
padding: EdgeInsetsDirectional.only(start: 24.0),
child: Icon(
widget.prefixIcon,
color: Colors.black,
)),
suffixIcon: Padding(
padding: EdgeInsetsDirectional.only(
start: 2.0, end: _hasdeleteIcon ? 20.0 : 0),
child: _hasdeleteIcon
? new InkWell(
onTap: (() {
setState(() {
widget.controller.text = '';
_hasdeleteIcon = false;
});
}),
child: Icon(
Icons.clear,
size: 18.0,
color: Colors.black,
))
: new Text('')),
contentPadding: EdgeInsets.fromLTRB(0, 10, 0, 0),
filled: true,
fillColor: Colors.transparent,
border: InputBorder.none,
),
onChanged: (str) {
setState(() {
if (str.isEmpty) {
_hasdeleteIcon = false;
} else {
_hasdeleteIcon = true;
}
});
},
onEditingComplete: widget.onEditingComplete)))
],
),
preferredSize: Size.fromHeight(widget.height));
}
}
static Widget buildAppBar(BuildContext context, String text,
{double fontSize: 18.0,
double height: 46.0,
double elevation: 0.5,
Widget leading,
bool centerTitle: false}) {
return new PreferredSize(
child: new AppBar(
elevation: elevation, //阴影
centerTitle: centerTitle,
title: Text(text, style: TextStyle(fontSize: fontSize)),
leading: leading),
preferredSize: Size.fromHeight(height));
}
3、引用
appBar: new SearchAppBarWidget(
focusNode: _focusNode,
controller: _controller,
elevation: 2.0,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
}),
inputFormatters: [
LengthLimitingTextInputFormatter(50),
],
onEditingComplete: () => _checkInput()),
网友评论