美文网首页
Flutter会动的搜索栏AppBar

Flutter会动的搜索栏AppBar

作者: 倪大头 | 来源:发表于2023-08-08 15:01 被阅读0次
    509_1691563632.gif

    利用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');
        },
    )
    

    相关文章

      网友评论

          本文标题:Flutter会动的搜索栏AppBar

          本文链接:https://www.haomeiwen.com/subject/dfwnpdtx.html