在这里插入图片描述

前言

消息输入框是社交应用中用户交互最频繁的组件之一。一个优秀的输入框组件需要支持文本输入、表情选择、附件发送等多种功能,同时还要具备良好的用户体验和性能表现。本文将深入讲解如何在Flutter和OpenHarmony平台上构建功能完善的消息输入框组件。

Flutter消息输入框实现

我们首先来实现Flutter版本的消息输入框,包含文本输入、发送按钮和附件按钮。

class MessageInputBar extends StatefulWidget {
  final Function(String) onSend;
  final VoidCallback? onAttachmentTap;
  
  const MessageInputBar({
    Key? key,
    required this.onSend,
    this.onAttachmentTap,
  }) : super(key: key);
  
  
  State<MessageInputBar> createState() => _MessageInputBarState();
}

组件定义为StatefulWidget因为需要管理输入框的状态。onSend回调在用户发送消息时触发,onAttachmentTap处理附件按钮点击。

class _MessageInputBarState extends State<MessageInputBar> {
  final TextEditingController _controller = TextEditingController();
  bool _hasText = false;
  
  
  void initState() {
    super.initState();
    _controller.addListener(_onTextChanged);
  }
  
  void _onTextChanged() {
    setState(() {
      _hasText = _controller.text.trim().isNotEmpty;
    });
  }

State类中定义TextEditingController来管理输入内容。_hasText状态变量追踪输入框是否有内容,用于控制发送按钮的显示状态。在initState中添加监听器,每当文本变化时更新状态。这种响应式设计确保UI始终与数据同步。

  
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
      decoration: BoxDecoration(
        color: Colors.white,
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.05),
            blurRadius: 10,
            offset: Offset(0, -2),
          ),
        ],
      ),

Container设置内边距和装饰样式。boxShadow创建向上的阴影效果,让输入栏与聊天内容区域形成视觉分隔。阴影透明度设置为5%,既能起到分隔作用又不会过于突兀,符合现代UI设计的轻量化趋势。

      child: SafeArea(
        top: false,
        child: Row(
          children: [
            IconButton(
              icon: Icon(Icons.add_circle_outline),
              color: Colors.grey[600],
              onPressed: widget.onAttachmentTap,
            ),

SafeArea确保在有底部安全区域的设备上正确显示。Row组件水平排列各个子元素。附件按钮使用IconButton实现,图标颜色设置为灰色,与整体设计风格协调。点击时触发父组件传入的回调函数。

            Expanded(
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 16),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.circular(24),
                ),
                child: TextField(
                  controller: _controller,
                  maxLines: 4,
                  minLines: 1,
                  decoration: InputDecoration(
                    hintText: '输入消息...',
                    border: InputBorder.none,
                  ),
                ),
              ),
            ),

Expanded让输入框占据剩余空间。外层Container创建圆角背景,内部TextField支持多行输入,maxLines限制最大行数防止输入框过度扩展。InputDecoration移除默认边框,hintText提供输入提示。这种设计让输入框看起来更加现代简洁。

            SizedBox(width: 8),
            AnimatedSwitcher(
              duration: Duration(milliseconds: 200),
              child: _hasText
                ? IconButton(
                    key: ValueKey('send'),
                    icon: Icon(Icons.send),
                    color: Colors.blue,
                    onPressed: _sendMessage,
                  )
                : IconButton(
                    key: ValueKey('mic'),
                    icon: Icon(Icons.mic),
                    color: Colors.grey[600],
                    onPressed: () {},
                  ),
            ),
          ],
        ),
      ),
    );
  }

AnimatedSwitcher实现发送按钮和语音按钮之间的平滑切换动画。当输入框有内容时显示蓝色发送按钮,否则显示灰色麦克风按钮。ValueKey确保动画正确识别不同的子组件。200毫秒的动画时长恰到好处,既能让用户感知到变化又不会造成等待感。

  void _sendMessage() {
    if (_controller.text.trim().isNotEmpty) {
      widget.onSend(_controller.text.trim());
      _controller.clear();
    }
  }
  
  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

_sendMessage方法处理消息发送逻辑,发送后清空输入框。dispose方法释放TextEditingController资源,防止内存泄漏。这是Flutter开发中的最佳实践,每个Controller都应该在组件销毁时正确释放。

OpenHarmony ArkTS实现

现在来看鸿蒙系统上的实现方案。

@Component
struct MessageInputBar {
  @State inputText: string = ''
  onSend: (message: string) => void = () => {}
  onAttachmentTap: () => void = () => {}
  
  build() {
    Row() {
      Image($r('app.media.ic_add'))
        .width(28)
        .height(28)
        .margin({ left: 12 })
        .onClick(() => this.onAttachmentTap())

@State装饰器声明响应式状态变量inputText。回调函数使用箭头函数语法定义默认空实现。Row作为根容器水平排列子元素。附件按钮使用Image组件加载本地图标资源,onClick绑定点击事件。

      TextInput({ placeholder: '输入消息...', text: this.inputText })
        .layoutWeight(1)
        .height(40)
        .backgroundColor('#F5F5F5')
        .borderRadius(20)
        .padding({ left: 16, right: 16 })
        .margin({ left: 8, right: 8 })
        .onChange((value: string) => {
          this.inputText = value
        })

TextInput组件实现文本输入功能,placeholder设置提示文字,text绑定状态变量实现双向数据绑定。layoutWeight(1)让输入框占据剩余空间,相当于Flutter的Expanded。onChange回调在输入变化时更新状态。圆角和背景色设置与Flutter版本保持一致的视觉风格。

      if (this.inputText.trim().length > 0) {
        Image($r('app.media.ic_send'))
          .width(28)
          .height(28)
          .margin({ right: 12 })
          .onClick(() => this.handleSend())
      } else {
        Image($r('app.media.ic_mic'))
          .width(28)
          .height(28)
          .margin({ right: 12 })
          .onClick(() => {})
      }
    }
    .width('100%')
    .height(56)
    .backgroundColor(Color.White)
  }

条件渲染根据输入内容切换发送按钮和麦克风按钮。ArkTS的条件渲染语法更加直观,直接使用if-else语句。整个Row设置固定高度和白色背景,形成清晰的输入区域。

  handleSend() {
    if (this.inputText.trim().length > 0) {
      this.onSend(this.inputText.trim())
      this.inputText = ''
    }
  }
}

handleSend方法封装发送逻辑,发送成功后清空输入框。由于inputText是响应式状态,清空后UI会自动更新,无需手动触发刷新。

总结

本文详细介绍了消息输入框组件在Flutter和OpenHarmony两个平台上的实现。输入框组件虽然看起来简单,但涉及状态管理、事件处理、动画效果等多个技术点。两个平台的实现思路相似,都采用响应式状态管理和条件渲染。在实际项目中,还可以扩展表情选择、@提及、话题标签等高级功能。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐