flutter组件-IntrinsicWidth可使宽度适应最小值

 

 

 

 主要是记录这种输入框的宽度自适应剩余空间

import 'dart:async';

import 'package:crm/widgets/iconfont.dart';
import 'package:flutter/material.dart';
import 'package:flutter_snsoft/flutter_snsoft.dart';
import 'package:flutter_snsoft/widgets/button/button.dart';

import 'button/button.dart';

const Duration _kExpand = Duration(milliseconds: 0);

class Inputlabel extends StatefulWidget {
  /// 标签文字宽度
  final double labelWidth;

  /// 标签文字
  final String label;

  ///  显示密送
  final ValueNotifier<bool>? showCC;

  /// 点击密送回调
  final VoidCallback? onCCTap;

  /// 收件人列表

  final ValueNotifier<List<Map<String, dynamic>>> addresseeList;

  /// 输入框失去焦点的回调
  final VoidCallback? onBlur;

  /// 输入框获得焦点
  final VoidCallback? onFocus;

  /// 添加收件人|抄送人|密送人
  final VoidCallback? onAddMail;
  final bool? autoFocus;
  final textController;
  final focusNode;

  ///数据校验和重新返回数据
  final Map<String, dynamic> Function(String)? rebuildFunc;
  const Inputlabel(
      {Key? key,
      this.labelWidth = 60,
      required this.label,
      this.focusNode,
      this.textController,
      this.showCC,
      this.onCCTap,
      this.onBlur,
      this.onFocus,
      required this.addresseeList,
      this.onAddMail,
      this.autoFocus = false,
      this.rebuildFunc})
      : super(key: key);

  @override
  _InputlabelState createState() => _InputlabelState();
}

class _InputlabelState extends State<Inputlabel>
    with SingleTickerProviderStateMixin {
  // 动画控制器
  late AnimationController _animationController;

  late ValueNotifier<bool> showAddLinkman; //选择联系人
  late bool _isExpanded; //是否是展开状态
  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(duration: _kExpand, vsync: this);
    _isExpanded = true;
    showAddLinkman = ValueNotifier(false);
    // widget.focusNode = FocusNode();
    // widget.focusNode.addListener(_onBlur);
  }

  @override
  void dispose() {
    // widget.focusNode.removeListener(_onBlur);
    widget.focusNode.dispose();
    _animationController.dispose();
    super.dispose();
  }

  void onItemDelete(int i) {
    widget.addresseeList.value.removeAt(i);
    widget.addresseeList.value = [...widget.addresseeList.value];
  }

// 点击键盘完成按钮的回调
  void onEditingComplete([bool clear = true]) {
    if (widget.textController.text.trim() == "") {
      return;
    }
    Map<String, dynamic>? res = checkText(widget.textController.text);
    if (res == null) {
      return;
    }
    String name = getValue(res, "name", widget.textController.text);
    String addr = getValue(res, "addr", widget.textController.text);
    widget.addresseeList.value = [
      ...widget.addresseeList.value,
      {
        "name": name,
        "addr": addr,
      }
    ];
    if (clear) {
      Timer(Duration(milliseconds: 10), () {
        widget.textController.clear();
      });
    }
  }

  Map<String, dynamic>? checkText(String value) {
    Map<String, dynamic> res = {"name": value, "addr": value};
    if (widget.rebuildFunc != null) {
      res = widget.rebuildFunc!(widget.textController.text);
      if (getValue(res, "err", false)) {
        Toast.show(getValue(res, "errmsg", "请检查输入信息"));
        return null;
      }
    }
    return res;
  }

  void _onBlur() {
    if (widget.focusNode.hasFocus) {
      _isExpanded = true;
      showAddLinkman.value = true;
      setState(() {
        _animationController.forward();
      });
      if (widget.onFocus != null) {
        widget.onFocus!();
      }
    } else {
      // 失去焦点的时候先插入一次
      onEditingComplete();
      showAddLinkman.value = false;
      // _isExpanded = false;
      _animationController.reverse().then<void>((void value) {
        if (!mounted) return;
        setState(() {
          // Rebuild without widget.children.
        });
      });
      if (widget.onBlur != null) {
        widget.onBlur!();
      }
    }
  }

  void onEdit(int i, String email) {
    onEditingComplete(false);
    widget.textController.text = email;
    widget.textController.selection = TextSelection.fromPosition(
        TextPosition(affinity: TextAffinity.downstream, offset: email.length));
    widget.addresseeList.value.removeAt(i);
    widget.addresseeList.value = [...widget.addresseeList.value];
  }

  Widget _buildChildren(context, child) {
    return GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          FocusScope.of(context).requestFocus(widget.focusNode);
        },
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              padding: const EdgeInsets.fromLTRB(16, 4, 16, 0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(
                    width: widget.labelWidth,
                    height: 28,
                    child: Align(
                      alignment: Alignment.centerLeft,
                      child: Text(
                        widget.label,
                        style: TextStyle(
                            fontSize: 15,
                            color: Colors.black,
                            fontWeight: FontWeight.w500,
                            height: 1),
                      ),
                    ),
                  ),
                  Expanded(
                    child: child,
                  ),
                  if (widget.showCC != null)
                    ValueListenableBuilder(
                      valueListenable: widget.showCC!,
                      builder: (context, bool val, child) {
                        if (!val) {
                          return SizedBox(
                            height: 28,
                            child: Center(
                              child: TextsButton(
                                text: "密送",
                                color: Colors.black,
                                onTap: widget.onCCTap,
                                lineHeight: 1,
                              ),
                            ),
                          );
                        } else {
                          return SizedBox(
                            height: 28,
                            child: Center(
                              child: TextsButton(
                                text: "取消密送",
                                color: Colors.black,
                                onTap: widget.onCCTap,
                                lineHeight: 1,
                              ),
                            ),
                          );
                        }
                      },
                    ),
                  WIconButton(
                    icon: CRMIcon.xieyoujian_jiashoujianren,
                    iconSize: 20,
                    iconColor: Colors.black,
                    padding: const EdgeInsets.fromLTRB(8, 3, 0, 8),
                    onTap: widget.onAddMail!,
                  )
                  // Transform.translate(
                  //   offset: const Offset(0, -2),
                  //   child: ValueListenableBuilder(
                  //     valueListenable: showAddLinkman,
                  //     builder: (context, bool value, child) {
                  //       return Offstage(
                  //         offstage: value,
                  //         child: WIconButton(
                  //           icon: Icons.add,
                  //           iconSize: 20,
                  //           iconColor: Colors.black,
                  //           padding: const EdgeInsets.fromLTRB(8, 5, 0, 8),
                  //           onTap: widget.onAddMail!,
                  //         ),
                  //       );
                  //     },
                  //   ),
                  // ),
                ],
              ),
            ),
            const Divider(height: 12),
          ],
        ));
  }

  @override
  Widget build(BuildContext context) {
    final bool closed = !_isExpanded && _animationController.isDismissed;
    final Widget result = Offstage(
        child: TickerMode(
          child: _Linkmans(
            children: widget.addresseeList,
            onItemTap: onItemDelete,
            onEdit: onEdit,
            autoFocus: widget.autoFocus!,
            controller: widget.textController,
            focusNode: widget.focusNode,
            onEditingComplete: onEditingComplete,
          ),
          enabled: !closed,
        ),
        offstage: closed);

    return AnimatedBuilder(
      animation: _animationController.view,
      builder: _buildChildren,
      child: result,
    );
  }
}

class _Input extends StatelessWidget {
  ///输入控制器
  final TextEditingController controller;

  /// 焦点管理
  final FocusNode? focusNode;

  /// 键盘确定事件
  final VoidCallback? onEditingComplete;

  final bool autoFocus;

  const _Input(
      {Key? key,
      required this.controller,
      this.focusNode,
      this.onEditingComplete,
      this.autoFocus = false})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return IntrinsicWidth(
      child: TextField(
        autofocus: autoFocus,
        controller: controller,
        cursorColor: Colors.black,
        cursorWidth: 1,
        cursorHeight: 18,
        scrollPadding: EdgeInsets.zero,
        focusNode: focusNode,
        decoration: const InputDecoration(
          border: InputBorder.none,
          contentPadding: EdgeInsets.all(5),
          isDense: true,
        ),
        style: const TextStyle(height: 1),
        onEditingComplete: onEditingComplete,
      ),
    );
  }
}

class _Linkmans extends StatefulWidget {
// 要渲染的收件人
  final ValueNotifier<List<Map>> children;

  /// 子组件点击事件
  final ValueChanged<int>? onItemTap;

  /// 子组件点击编辑
  final Function(int, String)? onEdit;
  final autoFocus;
  final controller;
  final focusNode;
  final onEditingComplete;

  const _Linkmans(
      {Key? key,
      required this.children,
      this.onItemTap,
      this.onEdit,
      this.autoFocus,
      this.controller,
      this.focusNode,
      this.onEditingComplete})
      : super(key: key);
  @override
  _LinkmansState createState() => _LinkmansState();
}

class _LinkmansState extends State<_Linkmans> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  void _onEdit(int i, String email) {
    if (widget.onEdit != null) {
      widget.onEdit!(i, email);
    }
  }

  List<Widget> buildChildren(List list) {
    List<Widget> res = [];
    for (int i = 0; i < list.length; i++) {
      res.add(EmailText(
        name: list[i]["name"] ?? list[i]["addr"] ?? "",
        email: list[i]["addr"] ?? "",
        onTap: () => onTap(i),
        onEdit: () => _onEdit(i, list[i]["addr"] ?? ""),
      ));
    }
    res.add(_Input(
      autoFocus: widget.autoFocus!,
      controller: widget.controller,
      focusNode: widget.focusNode,
      onEditingComplete: widget.onEditingComplete,
    ));
    return res;
  }

  void onTap(int i) {
    if (widget.onItemTap != null) {
      widget.onItemTap!(i);
    }
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: widget.children,
      builder: (context, List children, child) {
        return Padding(
          padding: const EdgeInsets.only(right: 2, left: 2),
          child: Wrap(
            spacing: 8,
            runSpacing: 8,
            children: buildChildren(children),
          ),
        );
      },
    );
  }
}

class EmailText extends StatelessWidget {
  /// 对于手工录入的邮箱来说,name和email的值是相等的
  ///
  ///名称
  final String? name;

  /// 邮箱
  final String? email;

  ///点击回调
  final VoidCallback? onTap;

  ///重新编辑邮箱
  final VoidCallback? onEdit;

  const EmailText({Key? key, this.name, this.email, this.onTap, this.onEdit})
      : super(key: key);
  @override
  Widget build(BuildContext context) {
    // 录入的信息是不是一个有效的邮箱地址
    bool _isEmail = isMailLegal(email!.trim());
    late ValueNotifier<bool> isEml = ValueNotifier(_isEmail);
    // 获取邮箱的背景色
    Color _normalBgColor = _isEmail ? Color(0xffe7f1ff) : Color(0xffffe8ee);
    String _name;
    if (isMailLegal(name!.trim())) {
      // 如果是手动录入的邮箱
      var list = name!.trim().split("@");
      _name = subString(list[0], 0, 10) + "@" + list[1];
    } else {
      _name = subString(name!.trim(), 0, 6);
    }
    return GestureDetector(
      onTap: onEdit,
      child: Container(
        height: 28,
        padding: const EdgeInsets.fromLTRB(10, 2, 0, 0),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            ValueListenableBuilder(
              valueListenable: isEml,
              builder: (context, bool value, child) {
                return value
                    ? Container(
                        width: 24,
                        height: 24,
                        margin: const EdgeInsets.only(right: 6),
                        decoration: BoxDecoration(
                          color: const Color(0xff4b86fc),
                          borderRadius: BorderRadius.circular(12),
                        ),
                        alignment: Alignment.center,
                        child: Text(_name.substring(0, 1)),
                      )
                    : const SizedBox();
              },
            ),
            Text(
              _name,
              style: TextStyle(
                fontSize: 14,
                color: _isEmail ? Colors.black : Color(0xffff4377),
                height: 1,
              ),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
            WIconButton(
              icon: Icons.close,
              iconSize: 16,
              iconColor: Colors.black.withOpacity(0.2),
              padding: EdgeInsets.only(left: 6, right: 10, top: 5, bottom: 6),
              onTap: onTap!,
            ),
          ],
        ),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(14),
          color: _normalBgColor,
        ),
      ),
    );
  }
}

String subString(String text, int start, int maxLen) {
  if (text.length - start <= maxLen) {
    return text.substring(start);
  } else {
    return text.substring(start, maxLen) + "...";
  }
}
posted @ 2022-07-06 10:42  文磊啊~  阅读(801)  评论(0编辑  收藏  举报