大前端-BFEFlutter

Flutter自定义带搜索框的AppBar

2019-02-18  本文已影响1840人  buhuiming

刚起步学习Flutter,还是比较容易上手的。下面介绍一下自定义的带搜索框的AppBar。

项目地址(github


效果图

image.png
image.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()),
至此,一个简单带搜索框的appBar就完成了,外部引用和TextField差不多,需要扩展的属性可以自行添加。
上一篇 下一篇

猜你喜欢

热点阅读