Flutter聊天气泡插件chat_bubbles的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter聊天气泡插件chat_bubbles的使用

插件信息

Pub Version GitHub License GitHub forks GitHub stars GitHub last commit likes popularity pub points

chat_bubbles 是一个Flutter插件,提供了类似于WhatsApp的聊天气泡组件。它支持多种类型的聊天气泡、音频聊天气泡和日期标签,易于使用和集成。

快速开始

添加依赖

在项目的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  chat_bubbles: ^1.7.0

导入包

然后在需要使用的Dart文件中导入插件:

import 'package:chat_bubbles/chat_bubbles.dart';

使用示例

iMessage风格的聊天气泡

BubbleSpecialThree(
  text: 'Added iMessage shape bubbles',
  color: Color(0xFF1B97F3),
  tail: false,
  textStyle: TextStyle(
      color: Colors.white,
      fontSize: 16
  ),
),
BubbleSpecialThree(
  text: 'Please try and give some feedback on it!',
  color: Color(0xFF1B97F3),
  tail: true,
  textStyle: TextStyle(
    color: Colors.white,
    fontSize: 16
  ),
),
BubbleSpecialThree(
  text: 'Sure',
  color: Color(0xFFE8E8EE),
  tail: false,
  isSender: false,
),
BubbleSpecialThree(
  text: "I tried. It's awesome!!!",
  color: Color(0xFFE8E8EE),
  tail: false,
  isSender: false,
),
BubbleSpecialThree(
  text: "Thanks",
  color: Color(0xFFE8E8EE),
  tail: true,
  isSender: false,
)

单个聊天气泡

BubbleSpecialOne(
  text: 'Hi, How are you? ',
  isSender: false,
  color: Colors.purple.shade100,
  textStyle: TextStyle(
    fontSize: 20,
    color: Colors.purple,
    fontStyle: FontStyle.italic,
    fontWeight: FontWeight.bold,
  ),
)

音频聊天气泡

Duration duration = new Duration();
Duration position = new Duration();
bool isPlaying = false;
bool isLoading = false;
bool isPause = false;

BubbleNormalAudio(
  color: Color(0xFFE8E8EE),
  duration: duration.inSeconds.toDouble(),
  position: position.inSeconds.toDouble(),
  isPlaying: isPlaying,
  isLoading: isLoading,
  isPause: isPause,
  onSeekChanged: _changeSeek,
  onPlayPauseButtonClick: _playAudio,
  sent: true,
)

图片聊天气泡

BubbleNormalImage(
  id: 'id001',
  image: _image(),
  color: Colors.purpleAccent,
  tail: true,
  delivered: true,
)

日期标签

DateChip(
  date: new DateTime(2021, 5, 7),
  color: Color(0x558AD3D5),
)

消息栏

MessageBar(
  onSend: (_) => print(_),
  actions: [
    InkWell(
      child: Icon(
        Icons.add,
        color: Colors.black,
        size: 24,
      ),
      onTap: () {},
    ),
    Padding(
      padding: EdgeInsets.only(left: 8, right: 8),
      child: InkWell(
        child: Icon(
          Icons.camera_alt,
          color: Colors.green,
          size: 24,
        ),
        onTap: () {},
      ),
    ),
  ],
)

完整的聊天视图示例

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:chat_bubbles/chat_bubbles.dart';
import 'package:audioplayers/audioplayers.dart';
import "package:cached_network_image/cached_network_image.dart";

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'chat bubble example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'chat bubble example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;
  MyHomePage({Key? key, required this.title}) : super(key: key);

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

class _MyHomePageState extends State<MyHomePage> {
  AudioPlayer audioPlayer = new AudioPlayer();
  Duration? duration = new Duration();
  Duration? position = new Duration();
  bool isPlaying = false;
  bool isLoading = false;
  bool isPause = false;

  @override
  void initState() {
    super.initState();
    audioPlayer.onDurationChanged.listen((Duration d) {
      setState(() {
        duration = d;
        isLoading = false;
      });
    });
    audioPlayer.onPositionChanged.listen((Duration p) {
      if (isPlaying) {
        setState(() {
          position = p;
        });
      }
    });
    audioPlayer.onPlayerComplete.listen((event) {
      setState(() {
        isPlaying = false;
        duration = new Duration();
        position = new Duration();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final now = new DateTime.now();
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: [
          SingleChildScrollView(
            child: Column(
              children: <Widget>[
                BubbleNormalImage(
                  id: 'id001',
                  image: _image(),
                  color: Colors.purpleAccent,
                  tail: true,
                  delivered: true,
                ),
                BubbleNormalAudio(
                  color: Color(0xFFE8E8EE),
                  duration:
                      duration == null ? 0.0 : duration!.inSeconds.toDouble(),
                  position:
                      position == null ? 0.0 : position!.inSeconds.toDouble(),
                  isPlaying: isPlaying,
                  isLoading: isLoading,
                  isPause: isPause,
                  onSeekChanged: _changeSeek,
                  onPlayPauseButtonClick: _playAudio,
                  sent: true,
                ),
                BubbleNormal(
                  text: 'bubble normal with tail',
                  isSender: false,
                  color: Color(0xFF1B97F3),
                  tail: true,
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.white,
                  ),
                ),
                BubbleNormal(
                  text: 'bubble normal with tail',
                  isSender: true,
                  color: Color(0xFFE8E8EE),
                  tail: true,
                  sent: true,
                ),
                DateChip(
                  date: new DateTime(now.year, now.month, now.day - 2),
                ),
                BubbleNormal(
                  text: 'bubble normal without tail',
                  isSender: false,
                  color: Color(0xFF1B97F3),
                  tail: false,
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.white,
                  ),
                ),
                BubbleNormal(
                  text: 'bubble normal without tail',
                  color: Color(0xFFE8E8EE),
                  tail: false,
                  sent: true,
                  seen: true,
                  delivered: true,
                ),
                BubbleSpecialOne(
                  text: 'bubble special one with tail',
                  isSender: false,
                  color: Color(0xFF1B97F3),
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.white,
                  ),
                ),
                DateChip(
                  date: new DateTime(now.year, now.month, now.day - 1),
                ),
                BubbleSpecialOne(
                  text: 'bubble special one with tail',
                  color: Color(0xFFE8E8EE),
                  seen: true,
                ),
                BubbleSpecialOne(
                  text: 'bubble special one without tail',
                  isSender: false,
                  tail: false,
                  color: Color(0xFF1B97F3),
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.black,
                  ),
                ),
                BubbleSpecialOne(
                  text: 'bubble special one without tail',
                  tail: false,
                  color: Color(0xFFE8E8EE),
                  sent: true,
                ),
                BubbleSpecialTwo(
                  text: 'bubble special tow with tail',
                  isSender: false,
                  color: Color(0xFF1B97F3),
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.black,
                  ),
                ),
                DateChip(
                  date: now,
                ),
                BubbleSpecialTwo(
                  text: 'bubble special tow with tail',
                  isSender: true,
                  color: Color(0xFFE8E8EE),
                  sent: true,
                ),
                BubbleSpecialTwo(
                  text: 'bubble special tow without tail',
                  isSender: false,
                  tail: false,
                  color: Color(0xFF1B97F3),
                  textStyle: TextStyle(
                    fontSize: 20,
                    color: Colors.black,
                  ),
                ),
                BubbleSpecialTwo(
                  text: 'bubble special tow without tail',
                  tail: false,
                  color: Color(0xFFE8E8EE),
                  delivered: true,
                ),
                BubbleSpecialThree(
                  text: 'bubble special three without tail',
                  color: Color(0xFF1B97F3),
                  tail: false,
                  textStyle: TextStyle(color: Colors.white, fontSize: 16),
                ),
                BubbleSpecialThree(
                  text: 'bubble special three with tail',
                  color: Color(0xFF1B97F3),
                  tail: true,
                  textStyle: TextStyle(color: Colors.white, fontSize: 16),
                ),
                BubbleSpecialThree(
                  text: "bubble special three without tail",
                  color: Color(0xFFE8E8EE),
                  tail: false,
                  isSender: false,
                ),
                BubbleSpecialThree(
                  text: "bubble special three with tail",
                  color: Color(0xFFE8E8EE),
                  tail: true,
                  isSender: false,
                ),
                SizedBox(
                  height: 100,
                )
              ],
            ),
          ),
          MessageBar(
            onSend: (_) => print(_),
            actions: [
              InkWell(
                child: Icon(
                  Icons.add,
                  color: Colors.black,
                  size: 24,
                ),
                onTap: () {},
              ),
              Padding(
                padding: EdgeInsets.only(left: 8, right: 8),
                child: InkWell(
                  child: Icon(
                    Icons.camera_alt,
                    color: Colors.green,
                    size: 24,
                  ),
                  onTap: () {},
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget _image() {
    return Container(
      constraints: BoxConstraints(
        minHeight: 20.0,
        minWidth: 20.0,
      ),
      child: CachedNetworkImage(
        imageUrl: 'https://i.ibb.co/JCyT1kT/Asset-1.png',
        progressIndicatorBuilder: (context, url, downloadProgress) =>
            CircularProgressIndicator(value: downloadProgress.progress),
        errorWidget: (context, url, error) => const Icon(Icons.error),
      ),
    );
  }

  void _changeSeek(double value) {
    setState(() {
      audioPlayer.seek(new Duration(seconds: value.toInt()));
    });
  }

  void _playAudio() async {
    final url = 'https://download.samplelib.com/mp3/sample-15s.mp3';
    if (isPause) {
      await audioPlayer.resume();
      setState(() {
        isPlaying = true;
        isPause = false;
      });
    } else if (isPlaying) {
      await audioPlayer.pause();
      setState(() {
        isPlaying = false;
        isPause = true;
      });
    } else {
      log('play: loading');
      setState(() {
        isLoading = true;
      });
      await audioPlayer.play(UrlSource(url));
      log('play: loaded');
      setState(() {
        audioPlayer.getDuration().then(
              (value) => setState(() {
                log('init duration: $value');
                duration = value;
                isLoading = false;
              }),
            );
        audioPlayer.getCurrentPosition().then(
              (value) => setState(() {
                log('init position: $value');
                position = value;
              }),
            );
        isPlaying = true;
      });
    }
  }
}

问题反馈

如果您在使用过程中遇到任何问题,请随时通过 GitHub Issues 提交反馈。

希望这个插件能帮助您快速构建出漂亮的聊天界面!如果有更多需求或建议,欢迎提交Pull Request。


更多关于Flutter聊天气泡插件chat_bubbles的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter聊天气泡插件chat_bubbles的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用chat_bubbles插件来创建聊天气泡的示例代码。这个插件可以帮助你轻松地在Flutter应用中实现聊天界面的气泡效果。

首先,确保你的Flutter项目已经配置好并运行正常。然后,按照以下步骤添加并使用chat_bubbles插件。

1. 添加依赖

在你的pubspec.yaml文件中添加chat_bubbles依赖:

dependencies:
  flutter:
    sdk: flutter
  chat_bubbles: ^最新版本号  # 请替换为实际的最新版本号

然后运行flutter pub get来安装依赖。

2. 导入插件

在你的Flutter项目中,导入chat_bubbles插件:

import 'package:chat_bubbles/chat_bubbles.dart';

3. 创建聊天气泡布局

接下来,你可以在你的UI中使用ChatBubble组件来创建聊天气泡。以下是一个简单的示例,展示了如何创建一个包含多个聊天气泡的列表:

import 'package:flutter/material.dart';
import 'package:chat_bubbles/chat_bubbles.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Chat Bubbles Example'),
        ),
        body: ChatBubbleScreen(),
      ),
    );
  }
}

class ChatBubbleScreen extends StatelessWidget {
  final List<Map<String, dynamic>> messages = [
    {
      'sender': 'User1',
      'text': 'Hello, how are you?',
      'isMe': true,
    },
    {
      'sender': 'User2',
      'text': 'I\'m good, thanks! How about you?',
      'isMe': false,
    },
    {
      'sender': 'User1',
      'text': 'I\'m doing well, thanks for asking!',
      'isMe': true,
    },
  ];

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: messages.length,
      itemBuilder: (context, index) {
        Map<String, dynamic> message = messages[index];
        bool isMe = message['isMe'];

        return Padding(
          padding: const EdgeInsets.only(vertical: 8.0),
          child: ChatBubble(
            sender: message['sender'],
            text: message['text'],
            isMe: isMe,
            tail: ChatBubbleTail(
              color: isMe ? Colors.blue : Colors.grey,
            ),
            showSenderName: true,
            showTime: false,
            time: '12:34', // 这里可以设置为实际的时间
            alignment: isMe ? Alignment.topleft : Alignment.topright,
            onBubblePressed: () {
              // 点击气泡时的回调
              print('Bubble pressed: ${message['text']}');
            },
          ),
        );
      },
    );
  }
}

4. 运行应用

现在,你可以运行你的Flutter应用,并查看聊天气泡的效果。这个示例展示了如何创建一个简单的聊天界面,其中包含了发送者和接收者的消息,并且可以通过点击气泡来触发一个回调函数。

请注意,chat_bubbles插件的具体API和用法可能会随着版本的更新而有所变化,因此请参考插件的官方文档以获取最新的使用方法和示例代码。

回到顶部