欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter實現自定義搜索框AppBar的示例代碼

 更新時間:2022年04月13日 15:41:12   作者:老李code  
開發(fā)中,頁面頭部為搜索樣式的設計非常常見,為了可以像系統(tǒng)AppBar那樣使用,本文將利用Flutter自定義一個搜索框,感興趣的可以了解一下

介紹

開發(fā)中,頁面頭部為搜索樣式的設計非常常見,為了可以像系統(tǒng)AppBar那樣使用,這篇文章記錄下在Flutter中自定義一個通用的搜索框AppBar記錄。

功能點: 搜索框、返回鍵、清除搜索內容功能、鍵盤處理。

效果圖

實現步驟

首先我們先來看下AppBar的源碼,實現了PreferredSizeWidget類,我們可以知道這個類主要是控制AppBar的高度的,Scaffold腳手架里的AppBar的參數類型就是PreferredSizeWidget類型。

class AppBar extends StatefulWidget implements PreferredSizeWidget{
...
preferredSize = _PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height),
...

/// {@template flutter.material.appbar.toolbarHeight}
/// Defines the height of the toolbar component of an [AppBar].
///
/// By default, the value of `toolbarHeight` is [kToolbarHeight].
/// {@endtemplate}
final double? toolbarHeight;

...
/// The height of the toolbar component of the [AppBar].
const double kToolbarHeight = 56.0;

}

abstract class PreferredSizeWidget implements Widget {
  // 設置在不受約束下希望的大小
  // 設置高度:Size.fromHeight(myAppBarHeight)
  Size get preferredSize;
}

為了方便擴展,可以在Scaffold里使用,我們需要創(chuàng)建AppBarSearch類繼承有狀態(tài)StatefulWidget類并實現PreferredSizeWidget類,實現preferredSize方法,并設置高度。

class AppBarSearch extends StatefulWidget implements PreferredSizeWidget {

@override
Size get preferredSize => Size.fromHeight(height);

}

因為ScaffoldAppBar實現了狀態(tài)欄的適配,核心見下方源碼:

//獲取狀態(tài)欄高度
MediaQuery.of(context).padding.top;

這里我們直接返回AppBar,并進行改造。(當然這里也可以不返回AppBar我們自己處理狀態(tài)欄的高度也行)。

思路: AppBar title字段自定義輸入框,主要通過文本框監(jiān)聽實現清除搜索內容和顯示清除按鈕的功能,通過輸入框是否有焦點監(jiān)聽進行刷新布局,通過定義回調函數的方式來進行搜索內容的監(jiān)聽。

// 輸入框控制
_controller = widget.controller ?? TextEditingController();
// 焦點控制
_focusNode = widget.focusNode ?? FocusNode();
// 焦點獲取失去監(jiān)聽
_focusNode?.addListener(() => setState(() {}));
// 文本輸入監(jiān)聽
_controller?.addListener(() => setState(() {}));

鍵盤搜素監(jiān)聽:

只需設置TextField的這兩個屬性即可。

textInputAction: TextInputAction.search,
onSubmitted: widget.onSearch, //輸入框完成觸發(fā)

鍵盤彈出收起處理:

在iOS中鍵盤的處理是需要我們自己來進行處理的,我們需要的功能是點擊搜索框之外的地方失去焦點從而關閉鍵盤,這里我使用了處理鍵盤的一個插件:flutter_keyboard_visibility: ^5.1.0,在我們需要處理焦點事件頁面根布局使用KeyboardDismissOnTap外部包裹即可,這個插件還可以主動控制鍵盤的彈出和收起,有興趣的小伙伴可以了解下。

return KeyboardDismissOnTap(
    child: Material();

完整源碼

/// 搜索AppBar
class AppBarSearch extends StatefulWidget implements PreferredSizeWidget {
  AppBarSearch({
    Key? key,
    this.borderRadius = 10,
    this.autoFocus = false,
    this.focusNode,
    this.controller,
    this.height = 40,
    this.value,
    this.leading,
    this.backgroundColor,
    this.suffix,
    this.actions = const [],
    this.hintText,
    this.onTap,
    this.onClear,
    this.onCancel,
    this.onChanged,
    this.onSearch,
    this.onRightTap,
  }) : super(key: key);
  final double? borderRadius;
  final bool? autoFocus;
  final FocusNode? focusNode;
  final TextEditingController? controller;

  // 輸入框高度 默認40
  final double height;

  // 默認值
  final String? value;

  // 最前面的組件
  final Widget? leading;

  // 背景色
  final Color? backgroundColor;

  // 搜索框內部后綴組件
  final Widget? suffix;

  // 搜索框右側組件
  final List<Widget> actions;

  // 輸入框提示文字
  final String? hintText;

  // 輸入框點擊回調
  final VoidCallback? onTap;

  // 清除輸入框內容回調
  final VoidCallback? onClear;

  // 清除輸入框內容并取消輸入
  final VoidCallback? onCancel;

  // 輸入框內容改變
  final ValueChanged<String>? onChanged;

  // 點擊鍵盤搜索
  final ValueChanged<String>? onSearch;

  // 點擊右邊widget
  final VoidCallback? onRightTap;

  @override
  _AppBarSearchState createState() => _AppBarSearchState();

  @override
  Size get preferredSize => Size.fromHeight(height);
}

class _AppBarSearchState extends State<AppBarSearch> {
  TextEditingController? _controller;
  FocusNode? _focusNode;

  bool get isFocus => _focusNode?.hasFocus ?? false; //是否獲取焦點

  bool get isTextEmpty => _controller?.text.isEmpty ?? false; //輸入框是否為空

  bool get isActionEmpty => widget.actions.isEmpty; // 右邊布局是否為空

  bool isShowCancel = false;

  @override
  void initState() {
    _controller = widget.controller ?? TextEditingController();
    _focusNode = widget.focusNode ?? FocusNode();
    if (widget.value != null) _controller?.text = widget.value ?? "";
    // 焦點獲取失去監(jiān)聽
    _focusNode?.addListener(() => setState(() {}));
    // 文本輸入監(jiān)聽
    _controller?.addListener(() {
      setState(() {});
    });
    super.initState();
  }

  // 清除輸入框內容
  void _onClearInput() {
    setState(() {
      _controller?.clear();
    });
    widget.onClear?.call();
  }

  // 取消輸入框編輯失去焦點
  void _onCancelInput() {
    setState(() {
      _controller?.clear();
      _focusNode?.unfocus(); //失去焦點
    });
    // 執(zhí)行onCancel
    widget.onCancel?.call();
  }

  Widget _suffix() {
    if (!isTextEmpty) {
      return InkWell(
        onTap: _onClearInput,
        child: SizedBox(
          width: widget.height,
          height: widget.height,
          child: Icon(Icons.cancel, size: 22, color: Color(0xFF999999)),
        ),
      );
    }
    return widget.suffix ?? SizedBox();
  }

  List<Widget> _actions() {
    List<Widget> list = [];
    if (isFocus || !isTextEmpty) {
      list.add(InkWell(
        onTap: widget.onRightTap ?? _onCancelInput,
        child: Container(
          constraints: BoxConstraints(minWidth: 48.w),
          alignment: Alignment.center,
          child: MyText(
            '搜索',
            fontColor: MyColors.color_666666,
            fontSize: 14.sp,
          ),
        ),
      ));
    } else if (!isActionEmpty) {
      list.addAll(widget.actions);
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    return AppBar(
      backgroundColor: widget.backgroundColor,
      //陰影z軸
      elevation: 0,
      // 標題與其他控件的間隔
      titleSpacing: 0,
      leadingWidth: 40.w,
      leading: widget.leading ??
          InkWell(
            child: Icon(
              Icons.arrow_back_ios_outlined,
              color: MyColors.color_666666,
              size: 16.w,
            ),
            onTap: () {
              Routes.finish(context);
            },
          ),
      title: Container(
          margin: EdgeInsetsDirectional.only(end: 10.w),
          height: widget.height,
          decoration: BoxDecoration(
            color: Color(0xFFF2F2F2),
            borderRadius: BorderRadius.circular(widget.borderRadius ?? 0),
          ),
          child: Container(
            child: Row(
              children: [
                SizedBox(
                  width: widget.height,
                  height: widget.height,
                  child:
                      Icon(Icons.search, size: 20.w, color: Color(0xFF999999)),
                ),
                Expanded(
                  // 權重
                  flex: 1,
                  child: TextField(
                    autofocus: widget.autoFocus ?? false,
                    // 是否自動獲取焦點
                    focusNode: _focusNode,
                    // 焦點控制
                    controller: _controller,
                    // 與輸入框交互控制器
                    //裝飾
                    decoration: InputDecoration(
                      isDense: true,
                      border: InputBorder.none,
                      hintText: widget.hintText ?? '請輸入關鍵字',
                      hintStyle: TextStyle(
                          fontSize: 14.sp, color: MyColors.color_666666),
                    ),
                    style: TextStyle(
                      fontSize: 14.sp,
                      color: MyColors.color_333333,
                    ),
                    // 鍵盤動作右下角圖標
                    textInputAction: TextInputAction.search,
                    onTap: widget.onTap,
                    // 輸入框內容改變回調
                    onChanged: widget.onChanged,
                    onSubmitted: widget.onSearch, //輸入框完成觸發(fā)
                  ),
                ),
                _suffix(),
              ],
            ),
          )),
      actions: _actions(),
    );
  }

  @override
  void dispose() {
    _controller?.dispose();
    _focusNode?.dispose();
    super.dispose();
  }
}

總結

整體設計思路還是非常簡單的,主要就是通過兩個監(jiān)聽來控制我們想要達到的交互效果,還有就是對dart中函數Funcation作為對象的加深理解,通過自定義搜索AppBar可以了解系統(tǒng)到AppBar的一些設計思路,這里主要還是記錄下我個人在做這個組件過程中的一個思路,希望對大家有所幫助~

到此這篇關于Flutter實現自定義搜索框AppBar的示例代碼的文章就介紹到這了,更多相關Flutter搜索框內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論