Flutter会动的搜索栏AppBar

2023-08-08  本文已影响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');
    },
)
上一篇下一篇

猜你喜欢

热点阅读