/* * @Author: XianKaiQun * @Date: 2020-09-14 09:34:57 * @LastEditors: wjc * @LastEditTime: 2023-01-11 09:42:06 * @Description: */ import 'package:flutter/material.dart'; import 'package:wisdom_cli/src/assets.gen.dart'; import 'package:wisdom_cli/wisdom_cli.dart'; ///搜索组件 class WSearch extends StatefulWidget { WSearch({ Key? key, this.hintText, this.controller, this.onSubmitted, this.onCancel, this.onChanged, this.moonlight = true, this.isDark = false, this.padding, this.backColor, this.isStatic = false, this.isControlOutside = false, this.initValue, this.onInput, }) : super(key: key); final String? hintText; final TextEditingController? controller; final void Function(String value)? onSubmitted; final void Function(String value)? onChanged; final void Function()? onCancel; final void Function(bool value)? onInput; final EdgeInsetsGeometry? padding; final backColor; final String? initValue; final bool? isControlOutside; /// 搜索文字是否固定显示 final bool isStatic; ///朦胧层 final bool moonlight; /// 背景是否深色 默认是白色 final bool isDark; @override _WSearchState createState() => _WSearchState(); } class _WSearchState extends State { FocusNode? focusNode; TextEditingController? controller; GlobalKey globalKey = GlobalKey(); String? value; Size? size; Offset? offset; OverlayEntry? entry; bool hasEntry = false; @override void initState() { controller = new TextEditingController(); focusNode = new FocusNode(); value = widget.initValue ?? ''; if (widget.isControlOutside! && controller?.value != null) { controller!.value = TextEditingValue( text: widget.initValue ?? '', selection: TextSelection.fromPosition( TextPosition( affinity: TextAffinity.downstream, offset: value!.length), ), ); } focusNode!.addListener(onfocus); super.initState(); } @override void didUpdateWidget(WSearch oldWidget) { super.didUpdateWidget(oldWidget); if (widget.isControlOutside! && controller?.value != null) { controller!.value = TextEditingValue( text: widget.initValue ?? '', selection: TextSelection.fromPosition( TextPosition( affinity: TextAffinity.downstream, offset: value!.length), ), ); setState(() {}); } } ///获取焦点时,显示朦胧层。 ///通过globalKey获取当前input组件的绝对位置, ///然后通过[OverlayEntry]显示朦胧层铺满剩余位置, ///点击朦胧层触发`onCancel`事件 onfocus() { if (focusNode!.hasFocus && widget.moonlight) { final RenderBox renderBox = globalKey.currentContext!.findRenderObject() as RenderBox; offset = renderBox.localToGlobal(Offset.zero); size = renderBox.size; entry = OverlayEntry( builder: (_) { return Positioned.fill( top: offset!.dy + size!.height, child: GestureDetector( onTap: () => onCancel(), child: ColoredBox( color: Colors.black26, ), ), ); }, ); Overlay.of(context).insert(entry!); hasEntry = true; } else { hasEntry = false; entry?.remove(); } setState(() {}); } @override void dispose() { value = ''; focusNode!.dispose(); controller!.dispose(); if (hasEntry) { entry!.remove(); } super.dispose(); } void onCancel() { setState(() { value = ''; controller!.clear(); focusNode!.unfocus(); if (widget.onInput != null) { widget.onInput!(false); } if (widget.onCancel != null) { widget.onCancel!(); } }); } void onSubmitted(String v) { value = v; controller!.value = TextEditingValue( text: value!, selection: TextSelection.fromPosition( TextPosition(affinity: TextAffinity.downstream, offset: value!.length), ), ); setState(() {}); if (widget.onSubmitted != null) { widget.onSubmitted!(v); } if (widget.onInput != null) { widget.onInput!(false); } } void onChanged(String v) { value = v; setState(() {}); if (widget.onChanged != null) { widget.onChanged!(v); } if (widget.onInput != null) { widget.onInput!(false); } } @override Widget build(BuildContext context) { final style = WTheme.of(context); final colorScheme = style.colorScheme; final _isStatic = widget.isStatic; return Wisdom.row( key: globalKey, padding: widget.padding ?? EdgeInsets.symmetric(vertical: 12.pt), color: widget.backColor ?? Colors.transparent, children: [ SizedBox(width: 15.pt), TextFormField( onTap: () => { if (widget.onInput != null) { widget.onInput!(true), } }, controller: controller, onFieldSubmitted: onSubmitted, focusNode: focusNode, onChanged: onChanged, textInputAction: TextInputAction.search, style: TextStyle( fontSize: 15.pt, textBaseline: TextBaseline.alphabetic, ), decoration: InputDecoration( hintText: widget.hintText, isCollapsed: true, hintStyle: TextStyle( color: Color(0xff999999), fontSize: 14.pt, textBaseline: TextBaseline.alphabetic, ), prefixIcon: Image( image: AssetList.$search_png_image, height: 15.pt, ), prefixIconConstraints: BoxConstraints( minWidth: 32.pt, ), // suffix: Text.rich( // WidgetSpan( // alignment: PlaceholderAlignment.middle, // baseline: TextBaseline.alphabetic, // child: WDot.delete( // onTap: () => { // value = '', // controller.clear(), // setState(() {}), // }, // color: Colors.black12, // iconTheme: IconThemeData(color: Colors.grey, size: 13.pt), // ), // ), // ), filled: true, isDense: true, fillColor: widget.isDark ? colorScheme.background4 : Colors.white, contentPadding: EdgeInsets.symmetric(vertical: 11.pt), enabledBorder: UnderlineInputBorder( /// 边框不设置一个值会有个黑边 borderSide: BorderSide(color: Colors.white, width: 0.1.pt), borderRadius: BorderRadius.circular(25.pt), ), focusedBorder: UnderlineInputBorder( /// 边框不设置一个值会有个黑边 borderSide: BorderSide(color: Colors.white, width: 0.1.pt), borderRadius: BorderRadius.circular(25.pt), ), ), ).nestExpanded(), if (!focusNode!.hasFocus && !_isStatic) SizedBox(width: 15.pt), if (_isStatic) Wisdom( onTap: () => { onSubmitted(value!), focusNode!.unfocus(), }, alignment: Alignment.center, margin: EdgeInsets.symmetric(horizontal: 5.pt), padding: EdgeInsets.symmetric(horizontal: 10.pt), child: WisText( '搜索', size: 14.pt, color: colorScheme.primary, weight: FontWeight.w400, textAlign: TextAlign.center, ), ), if (focusNode!.hasFocus && !_isStatic) Wisdom( onTap: () => onCancel(), height: 25.pt, alignment: Alignment.center, margin: EdgeInsets.symmetric(horizontal: 5.pt), padding: EdgeInsets.symmetric(horizontal: 10.pt), child: Text( '取消', textAlign: TextAlign.center, style: TextStyle(fontSize: 13.pt), ), ), ], ); } }