Flutter聊天列表展示插件lorien_chat_list的使用

Flutter聊天列表展示插件lorien_chat_list的使用

lorien_chat_list 是一个用于构建类似Messenger或WhatsApp聊天页面的包。与其他包的主要区别在于滚动部分——当有新消息时会自动滚动到底部,或者如果用户已经向上滚动了一定距离,则保持当前滚动位置(您可以设置该阈值)。

lorien_dev_chat_list_demo_short

开始使用

pubspec.yaml 文件中添加依赖:

dependencies:
  ...
  lorien_chat_list: ^0.0.1

基本用法

导入

import 'package:lorien_chat_list/lorien_chat_list.dart';

控制器

final ChatListController<int> _controller = ChatListController(
  initialItems: List.generate(10, (index) => index),
);

添加项目到列表底部:

_controller.addToBottom(100);

添加一系列项目到列表底部:

_controller.addRangeToBottom([100, 200]);

添加项目到列表顶部:

_controller.addToTop(-100);

添加一系列项目到列表顶部:

_controller.addRangeToTop([-100, -200]);

清除所有项目并重置控制器到初始状态:

_controller.clearAll();

小部件

ChatList(
  controller: _controller,
  itemBuilder: (item, properties) => Text(
    '${item.toString()} - ${properties.toString()}',
  ),
),

自定义(可选)

ChatList

  • loadingMoreWidget - 在加载更多旧消息时(onLoadMoreCallback)可见的顶部小部件
  • onLoadMoreCallback - 加载更多旧消息的函数。当达到列表顶部边缘时触发。应返回布尔值,true 表示还有更多的旧消息可以加载,否则 false 表示已加载完毕。
  • scrollController - 滚动控制器
  • scrollPhysics - 滚动物理特性
  • padding - 列表填充
  • spacing - 项目之间的垂直间距
  • useJumpTo - 是否使用 jumpTo 而不是 animateTo 进行自动滚动
  • animateToDuration - animateTo 的持续时间,默认为 300 毫秒
  • fadeInDuration - 淡入持续时间,默认为 300 毫秒
  • animateToCurve - animateTo 的曲线,默认为 Curves.easeInOut
  • fadeInCurve - 淡入曲线,默认为 Curves.easeInOut
  • bottomEdgeThreshold - 自动滚动到底部项目的阈值,默认为 0

示例代码

以下是一个完整的示例代码,展示了如何使用 lorien_chat_list 包来创建一个聊天列表页面:

import 'dart:math';

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

void main() {
  runApp(const LorienChatListExample());
}

class LorienChatListExample extends StatefulWidget {
  const LorienChatListExample({super.key});

  [@override](/user/override)
  State<LorienChatListExample> createState() => _LorienChatListExampleState();
}

class _LorienChatListExampleState extends State<LorienChatListExample> {
  late final ChatListController<_MessageModel> _chatController = ChatListController(
    initialItems: List.generate(10, (index) => -index)
        .map(
          (number) => _MessageModel(
            number: number,
            isMyMessage: _random.nextBool(),
            text: _tolkienQuotes[number % _tolkienQuotes.length],
          ),
        )
        .toList(),
  );

  int _nextTopNumber = -10;
  int _nextBottomNumber = 1;

  final _random = Random();
  final _scrollController = ScrollController();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.grey[200],
        appBar: AppBar(
          backgroundColor: Colors.black,
          title: const Text(
            'LORIEN.DEV Chat list',
            style: TextStyle(
              color: Colors.white,
            ),
          ),
          actions: [
            IconButton(
              tooltip: 'Add item to top',
              icon: const Icon(
                Icons.add_comment_outlined,
                color: Colors.white,
              ),
              onPressed: () => _chatController.addToTop(
                _MessageModel(
                  number: _nextTopNumber--,
                  isMyMessage: _random.nextBool(),
                  text: _tolkienQuotes[_nextTopNumber % _tolkienQuotes.length],
                ),
              ),
            ),
            IconButton(
              tooltip: 'Add item to bottom',
              icon: const Icon(
                Icons.add_comment,
                color: Colors.white,
              ),
              onPressed: () => _chatController.addToBottom(
                _MessageModel(
                  number: _nextBottomNumber++,
                  isMyMessage: _random.nextBool(),
                  text: _tolkienQuotes[_nextBottomNumber % _tolkienQuotes.length],
                ),
              ),
            ),
            IconButton(
              tooltip: 'Clear list',
              icon: const Icon(
                Icons.refresh,
                color: Colors.white,
              ),
              onPressed: () {
                _chatController.clearAll();
                _nextTopNumber = 0;
                _nextBottomNumber = 1;
              },
            ),
          ],
        ),
        body: ChatList(
          controller: _chatController,
          itemBuilder: (item, properties) => _MessageCard(
            type: item.isMyMessage
                ? _MessageType.outgoing
                : _MessageType.incoming,
            text: '${item.number}. ${item.text}',
          ),
          loadingMoreWidget: const Padding(
            padding: EdgeInsets.only(top: 16.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircularProgressIndicator(),
              ],
            ),
          ),
          onLoadMoreCallback: _loadMoreOldMessages,
          scrollController: _scrollController,
          scrollPhysics: const ClampingScrollPhysics(),
          useJumpTo: false,
          animateToDuration: const Duration(milliseconds: 300),
          fadeInDuration: const Duration(milliseconds: 300),
          animateToCurve: Curves.easeInOut,
          fadeInCurve: Curves.easeInOut,
          bottomEdgeThreshold: 20.0,
          padding: const EdgeInsets.all(16.0),
          spacing: 4.0,
        ),
      ),
    );
  }

  /// 模拟加载更多旧消息。
  /// 返回 *true* 如果还有更多的旧消息可以加载
  /// 否则返回 *false* 如果已加载完毕。
  Future<bool> _loadMoreOldMessages() async {
    /// 模拟延迟3秒
    await Future.delayed(const Duration(seconds: 3));

    /// 获取10个更多的旧消息
    final newOldItems = List.generate(10, (index) => _nextTopNumber--)
        .map(
          (number) => _MessageModel(
            number: number,
            isMyMessage: _random.nextBool(),
            text: _tolkienQuotes[number % _tolkienQuotes.length],
          ),
        )
        .toList();

    /// 将新的旧消息添加到聊天列表的顶部
    _chatController.addRangeToTop(newOldItems);

    /// 返回是否有更多的旧消息可以加载
    return _nextTopNumber > -30;
  }
}

class _MessageCard extends StatelessWidget {
  const _MessageCard({
    required _MessageType type,
    required String text,
  })  : _type = type,
        _text = text;

  final _MessageType _type;
  final String _text;

  [@override](/user/override)
  Widget build(BuildContext context) {
    final isIncoming = _type == _MessageType.incoming;
    return Row(
      mainAxisAlignment:
          isIncoming ? MainAxisAlignment.start : MainAxisAlignment.end,
      children: [
        Flexible(
          child: ConstrainedBox(
            constraints: BoxConstraints(
              maxWidth: MediaQuery.of(context).size.width * 0.7,
            ),
            child: Card(
              color: isIncoming ? Colors.white : Colors.black,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(
                  _text,
                  style: TextStyle(
                    color: isIncoming ? Colors.black : Colors.white,
                  ),
                  textAlign: isIncoming ? TextAlign.left : TextAlign.right,
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

class _MessageModel {
  const _MessageModel({
    required this.number,
    required this.isMyMessage,
    required this.text,
  });

  final int number;
  final bool isMyMessage;
  final String text;
}

enum _MessageType {
  incoming,
  outgoing,
}

const _tolkienQuotes = [
  "\"All we have to decide is what to do with the time that is given us.\" "
      "(The Fellowship of the Ring - J.R.R. Tolkien)",
  "\"Not all those who wander are lost.\" (The Fellowship of the Ring - J.R.R. Tolkien)",
  "\"Courage is found in unlikely places.\" (The Return of the King - J.R.R. Tolkien)",
  "\"Even the smallest person can change the course of the future.\" (The Fellowship of the Ring - J.R.R. Tolkien)",
  "\"It's a dangerous business, Frodo, going out your door. You step onto the road, "
      "and if you don't keep your feet, "
      "there's no knowing where you might be swept off to.\" (The Fellowship of the Ring - J.R.R. Tolkien)",
  "\"I will not say: do not weep; for not all tears are an evil.\" (The Return of the King - J.R.R. Tolkien)",
  "\"Far over the misty mountains cold, To dungeons deep and caverns old, We must away, ere break of day, To seek "
      "the pale enchanted gold.\" (The Hobbit - J.R.R. Tolkien)",
  "\"The world is indeed full of peril, and in it there are many dark places; but still there is much that is fair, "
      "and though in all lands love is now mingled with grief, it grows perhaps the greater.\" "
      "(The Fellowship of the Ring - J.R.R. Tolkien)",
  "\"War must be, while we defend our lives against a destroyer who would devour all; but I do not love the bright"
      " sword for its sharpness, nor the arrow for its swiftness, nor the warrior for his glory. I love only that"
      " which they defend.\" (The Two Towers - J.R.R. Tolkien)",
  "\"There are older and fouler things than Orcs in the deep places of the world.\" "
      "(The Fellowship of the Ring - J.R.R. Tolkien)"
];

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

1 回复

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


lorien_chat_list 是一个 Flutter 插件,用于展示聊天列表。它提供了丰富的功能,如消息气泡、头像、时间戳、未读消息计数等,可以帮助开发者快速构建一个功能完善的聊天界面。

安装插件

首先,你需要在 pubspec.yaml 文件中添加 lorien_chat_list 依赖:

dependencies:
  flutter:
    sdk: flutter
  lorien_chat_list: ^1.0.0 # 请使用最新版本

然后运行 flutter pub get 来安装插件。

基本使用

下面是一个简单的示例,展示了如何使用 lorien_chat_list 插件来展示聊天列表。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChatListScreen(),
    );
  }
}

class ChatListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Chat List'),
      ),
      body: LorienChatList(
        items: [
          ChatItem(
            name: 'John Doe',
            message: 'Hey, how are you?',
            time: '10:30 AM',
            avatar: 'https://via.placeholder.com/150',
            unreadCount: 2,
          ),
          ChatItem(
            name: 'Jane Smith',
            message: 'Can we meet tomorrow?',
            time: 'Yesterday',
            avatar: 'https://via.placeholder.com/150',
            unreadCount: 0,
          ),
          // Add more ChatItem objects here
        ],
        onItemTap: (ChatItem item) {
          print('Tapped on ${item.name}');
          // Navigate to chat detail screen or perform other actions
        },
      ),
    );
  }
}

参数说明

  • items: 一个 ChatItem 对象的列表,每个 ChatItem 代表一个聊天项。

    • name: 聊天对象的名称。
    • message: 最后一条消息的内容。
    • time: 最后一条消息的时间。
    • avatar: 聊天对象的头像 URL。
    • unreadCount: 未读消息的数量。
  • onItemTap: 当用户点击某个聊天项时触发的回调函数。

自定义样式

lorien_chat_list 提供了多种自定义选项,你可以通过传递不同的参数来调整聊天列表的外观。例如:

LorienChatList(
  items: [
    // ChatItem objects
  ],
  backgroundColor: Colors.white,
  itemBackgroundColor: Colors.grey[200],
  avatarRadius: 25,
  titleStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
  subtitleStyle: TextStyle(fontSize: 14, color: Colors.grey),
  timeStyle: TextStyle(fontSize: 12, color: Colors.grey[600]),
  unreadCountStyle: TextStyle(fontSize: 12, color: Colors.white),
  unreadCountBackgroundColor: Colors.red,
  onItemTap: (ChatItem item) {
    // Handle item tap
  },
);
回到顶部