flutter微信聊天输入框功能如何实现

作者:有用网 阅读量:197 发布时间:2024-01-04
关键字 Flutter

这篇文章主要讲解了“flutter微信聊天输入框功能如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“flutter微信聊天输入框功能如何实现”吧!

高仿微信聊天输入框,效果图如下(目前都是静态展示,服务还没开始开发):

大家如果观察仔细的话 应该会发现,他输入框下面的高度 刚好就是 软键盘的高度;所以在这里就需要监听软键盘的高度。还要配置

resizeToAvoidBottomInset: false,
   return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(

这里以 单聊为例:

遇到有个问题就是输入框行数的限制:这里这只 maxLines:null,就能自适应高度了。

就能做到 TextField多行输入了

child: TextField(
  // maxLength: maxLength,
  focusNode: focusNode,
  maxLines: null,
  maxLength: 200,
  cursorColor: AppColor.color3BAB71,
  controller: controller,
  textAlignVertical: TextAlignVertical.center,
  keyboardType: keyboardType,
  onEditingComplete: onEditingComplete,
  onSubmitted: onSubmitted,
  style: style ?? AppTextStyle.textStyle_28_333333,
  // inputFormatters: inputFormatters,
  decoration: InputDecoration(
    focusedBorder: const OutlineInputBorder(
        borderSide: BorderSide(width: 0, color: Colors.transparent)),
    disabledBorder: const OutlineInputBorder(
        borderSide: BorderSide(width: 0, color: Colors.transparent)),
    enabledBorder: const OutlineInputBorder(
        borderSide: BorderSide(width: 0, color: Colors.transparent)),
    border: OutlineInputBorder(
      borderSide: BorderSide.none,
      borderRadius: BorderRadius.circular(7.cale),
      //borderSide: BorderSide(width: 0, color: Colors.transparent),
      // borderSide: BorderSide(width: 0, color: Colors.transparent),
    ),
    hintText: hintText,
    prefixIcon: prefixIcon,
    prefixIconConstraints: prefixIconConstraints,
    hintStyle: hintStyle ?? AppTextStyle.textStyle_28_AAAAAA,
    counterText: '', //取消文字计数器
    // border: InputBorder.none,
    isDense: true,
    errorText: errorText,
    contentPadding: EdgeInsets.symmetric(
      horizontal: 16.cale,
      vertical: 20.cale,
    ),
  ),
  // contentPadding:
  //     EdgeInsets.only(left: 16.cale, right: 16.cale, top: 20.cale),
 
  // errorText: "输入错误",
),

代码结构如下:

flutter微信聊天输入框功能如何实现

--- chatCommon

        ------ chat_bottom.dart                 聊天底部输入框

        ------ chat_element_other.dart      聊天时别人信息的显示

        ------ chat_element_self.dart        聊天时自己信息的显示

        ------ chat_input_box.dart             聊天文本输入框封装

        ------ page_chat_group.dart         群聊

        ------ page_chat_person.dart       单聊

        ------ provider_chat_content.dart  聊天键盘显示 事件的传递 /键盘高度的处理

chat_bottom.dart

import 'package:flutter/material.dart';
import 'package:imflutter/const/app_textStyle.dart';
import 'package:imflutter/pages/chatCommon/provider_chat_content.dart';
import 'package:imflutter/wrap/extension/extension.dart';
import '../../const/app_colors.dart';
import '../../const/app_icon.dart';
import '../../wrap/widget/app_widget.dart';
import 'chat_input_box.dart';
 
class ChatBottom extends StatefulWidget {
  final ProviderChatContent providerChatContent;
  const ChatBottom({Key? key, required this.providerChatContent})
      : super(key: key);
 
  State<ChatBottom> createState() => _ChatBottomState();
}
 
class _ChatBottomState extends State<ChatBottom> with WidgetsBindingObserver {
  // 0 语音 1 键盘 2 表情
  int _inputType = 0;
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();
 
  bool get _keyboardShow => widget.providerChatContent.contentShow;
 
  final List<Map> _listOption = [
    {'title': '相册', 'icon': 'assets/common/chat/ic_details_photo.webp'},
    {'title': '拍照', 'icon': 'assets/common/chat/ic_details_camera.webp'},
    {'title': '视频通话', 'icon': 'assets/common/chat/ic_details_video.webp'},
    {'title': '位置', 'icon': 'assets/common/chat/ic_details_localtion.webp'},
    {'title': '红包', 'icon': 'assets/common/chat/ic_details_red.webp'},
    {'title': '转账', 'icon': 'assets/common/chat/ic_details_transfer.webp'},
    {'title': '语音输入', 'icon': 'assets/common/chat/ic_chat_voice.webp'},
    {'title': '我的收藏', 'icon': 'assets/common/chat/ic_details_favorite.webp'},
  ];
 
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _controller.addListener(() {
      setState(() {});
    });
    _focusNode.addListener(() {
      if (_focusNode.hasFocus) {
        widget.providerChatContent.updateContentShow(true);
      }
    });
  }
 
  @override
  Widget build(BuildContext context) {
    print('ChatBottom------------------------build');
    return Container(
      padding: EdgeInsets.symmetric(vertical: 20.cale),
      decoration: BoxDecoration(
        color: AppColor.colorF7F7F7,
        border: Border(
          top: BorderSide(width: 1.cale, color: AppColor.colordddddd),
        ),
      ),
      // height: 110.cale,
      child: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              AnimatedSwitcher(
                duration: const Duration(milliseconds: 20),
                transitionBuilder: (Widget child, Animation<double> animation) {
                  return FadeTransition(
                    opacity: animation,
                    child: child,
                  );
                },
                child: _inputType == 0
                    ? AppWidget.inkWellEffectNone(
                        key: const ValueKey("AppIcon.audio"),
                        onTap: () {
                          print('启动音频');
                          _inputType = 1;
                          widget.providerChatContent.updateContentShow(false);
                        },
                        child: Padding(
                          padding:
                              EdgeInsets.only(left: 20.cale, bottom: 15.cale),
                          child: Icon(
                            AppIcon.audio,
                            size: 50.cale,
                            color: Colors.black,
                          ),
                        ),
                      )
                    : AppWidget.inkWellEffectNone(
                        key: const ValueKey("AppIcon.keyboard"),
                        onTap: () {
                          _inputType = 0;
                          widget.providerChatContent.updateContentShow(true);
                          _focusNode.requestFocus();
                        },
                        child: Padding(
                          padding:
                              EdgeInsets.only(left: 20.cale, bottom: 15.cale),
                          child: Icon(
                            AppIcon.keyboard,
                            size: 50.cale,
                            color: Colors.black,
                          ),
                        ),
                      ),
              ),
              Expanded(
                child: _inputType == 0
                    ? Padding(
                        padding: EdgeInsets.symmetric(
                          horizontal: 20.cale,
                        ),
                        child: ChatInputBox(
                          style: AppTextStyle.textStyle_30_000000,
                          onEditingComplete: () {
                            print("onEditingComplete");
                          },
                          onSubmitted: (str) {
                            print("onSubmitted:$str");
                          },
                          controller: _controller,
                          focusNode: _focusNode,
                        ),
                      )
                    : AppWidget.inkWellEffectNone(
                        onTap: () {},
                        child: Container(
                          margin: EdgeInsets.symmetric(horizontal: 20.cale),
                          decoration: BoxDecoration(
                            color: Colors.white,
                            borderRadius: BorderRadius.circular(7.cale),
                          ),
                          height: 80.cale,
                          child: Center(
                            child: Text(
                              '按住 说话',
                              style: AppTextStyle.textStyle_30_000000,
                            ),
                          ),
                        ),
                      ),
              ),
              AppWidget.inkWellEffectNone(
                onTap: () {
                  print('添加表情符号');
                },
                child: Padding(
                  padding: EdgeInsets.only(bottom: 15.cale),
                  child: Icon(
                    AppIcon.faceHappy,
                    size: 50.cale,
                    color: Colors.black,
                  ),
                ),
              ),
              AnimatedSwitcher(
                duration: const Duration(milliseconds: 50),
                transitionBuilder: (Widget child, Animation<double> animation) {
                  return ScaleTransition(
                    scale: animation,
                    alignment: Alignment.centerRight,
                    child: FadeTransition(
                      opacity: animation,
                      child: child,
                    ),
                  );
                },
                child: _inputType == 0 && _controller.value.text.isNotEmpty
                    ? AppWidget.inkWellEffectNone(
                        key: const ValueKey('发送'),
                        onTap: () {
                          print('发送');
                          _controller.clear();
                        },
                        child: Container(
                          margin: EdgeInsets.only(
                              left: 20.cale, right: 24.cale, bottom: 10.cale),
                          padding: EdgeInsets.symmetric(
                            horizontal: 24.cale,
                            vertical: 10.cale,
                          ),
                          decoration: BoxDecoration(
                            color: AppColor.color05C160,
                            borderRadius: BorderRadius.circular(12.cale),
                          ),
                          child: Center(
                              child: Text(
                            '发送',
                            style: AppTextStyle.textStyle_30_FFFFFF,
                          )),
                        ),
                      )
                    : AppWidget.inkWellEffectNone(
                        key: const ValueKey('AppIcon.add'),
                        onTap: () {
                          print('添加附件 图片视频');
                          setState(() {
                            if (_focusNode.hasFocus) {
                              _focusNode.unfocus();
                            }
                            widget.providerChatContent.updateContentShow(true);
                            // print(
                            //     '---------${DataInheritedWidget.of(context)?.dataEnvironment.keyboardHeight}');
                            //InheritedKeyboard.of(context)?.updateKeyboard(true);
                          });
                        },
                        child: Padding(
                          padding: EdgeInsets.only(
                              left: 10.cale, right: 20.cale, bottom: 10.cale),
                          child: Icon(
                            AppIcon.add,
                            size: 58.cale,
                            color: Colors.black,
                          ),
                        ),
                      ),
              ),
            ],
          ),
          if (_keyboardShow)
            Container(
              width: double.infinity,
              margin: EdgeInsets.only(
                top: 20.cale,
              ),
              // padding: EdgeInsets.only(bottom: 200.cale),
              decoration: BoxDecoration(
                border: Border(
                  top: BorderSide(width: 1.cale, color: AppColor.colordddddd),
                ),
              ),
              height: widget.providerChatContent.keyboardHeight,
              child: Wrap(
                runAlignment: WrapAlignment.center,
                alignment: WrapAlignment.center,
                //crossAxisAlignment: WrapCrossAlignment.center,
                spacing: 75.cale,
                runSpacing: 60.cale,
                children: _listOption
                    .asMap()
                    .map(
                      (key, value) => MapEntry(
                        key,
                        SizedBox(
                          width: 100.cale,
                          height: 150.cale,
                          child: Column(
                            children: [
                              Container(
                                width: 100.cale,
                                height: 100.cale,
                                decoration: BoxDecoration(
                                  color: Colors.white,
                                  borderRadius: BorderRadius.circular(25.cale),
                                ),
                                child: Image.asset(
                                  value['icon'],
                                  w

#发表评论
提交评论