【Flutter 开发必备】AzListView 组件全解析,打造丝滑索引列表!

简介: 在 Flutter 开发中,AzListView 是实现字母索引分类列表的理想选择。它支持 A-Z 快速跳转、悬浮分组标题、自定义 UI 和高效性能,适用于通讯录、城市选择等场景。本文将详细解析 AzListView 的核心参数和实战示例,助你轻松实现流畅的索引列表。

【Flutter 开发必备】AzListView 组件全解析,打造丝滑索引列表!

在 Flutter 开发中,遇到需要按字母索引分类展示列表的需求怎么办?AzListView 组件让你的列表不仅美观,还能流畅滚动!今天,我们就来全面解析 AzListView 的用法,让你的 Flutter 开发更上一层楼!

🔥 为什么选择 AzListView?

在开发通讯录、城市选择等需要索引的列表时,普通 ListView 显然不够用,而 AzListView 提供了以下超强能力:

字母索引导航:支持 A-Z 索引快速跳转。
Sticky Headers:分组标题悬浮效果,让分类一目了然。
可定制 UI:支持灵活修改索引样式、列表样式。
高效性能:基于 ListView.builder,性能优秀,支持大数据量列表。

🛠 AzListView 组件核心参数解析

在使用 AzListView 之前,我们先来看一下它的核心参数:

参数名 类型 说明
data List\ 数据源,需继承 ISuspensionBean 接口
itemBuilder IndexedWidgetBuilder 列表项构建方法
suspensionWidget Widget 悬浮索引组件(分组标题)
indexBarOptions IndexBarOptions 索引栏配置,如颜色、字体等
header Widget 头部组件,可选

📌 实战示例:快速实现一个索引通讯录

接下来,我们用一个示例来展示 AzListView 的强大之处。

1️⃣ 准备数据

class Contact extends ISuspensionBean {
   
  String name;
  String tagIndex;
  Contact({
   required this.name, required this.tagIndex});

  @override
  String getSuspensionTag() => tagIndex;
}

List<Contact> contacts = [
  Contact(name: "Alice", tagIndex: "A"),
  Contact(name: "Bob", tagIndex: "B"),
  Contact(name: "Charlie", tagIndex: "C"),
];
AI 代码解读

2️⃣ 使用 AzListView 渲染 UI

AzListView(
  data: contacts,
  itemBuilder: (context, index) {
   
    final contact = contacts[index];
    return ListTile(
      title: Text(contact.name),
    );
  },
  suspensionWidget: Container(
    alignment: Alignment.centerLeft,
    color: Colors.blue,
    padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
    child: Text("索引", style: TextStyle(color: Colors.white, fontSize: 16)),
  ),
  indexBarOptions: IndexBarOptions(
    indexHintAlignment: Alignment.centerRight,
    indexHintTextStyle: TextStyle(color: Colors.white, fontSize: 24),
    indexHintDecoration: BoxDecoration(
      color: Colors.blueAccent,
      shape: BoxShape.circle,
    ),
  ),
)
AI 代码解读

3️⃣ 运行效果

运行后,你将会看到一个丝滑的索引列表,点击右侧索引还能快速跳转到相应分组!

🎨 高级玩法:自定义索引栏

如果想让索引栏更符合你的 UI 需求,可以使用 IndexBarOptions 进行自定义。

indexBarOptions: IndexBarOptions(
  needRebuild: true,
  indexBarMargin: EdgeInsets.all(10),
  indexHintOffset: Offset(-20, 0),
  selectTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
  selectItemDecoration: BoxDecoration(
    shape: BoxShape.circle,
    color: Colors.redAccent,
  ),
)
AI 代码解读

💡 总结

AzListView 让 Flutter 开发中的索引列表变得超级简单,无论是通讯录、城市列表还是分类商品,都可以轻松实现。掌握这些用法,你的应用将更加专业、流畅!

🔥 你在开发中遇到哪些列表索引的挑战?欢迎在评论区交流,一起学习进步!

完整示例如下:

import 'package:azlistview/azlistview.dart';
import "package:beehive/constants/constant.dart";
import "package:beehive/controllers/friend/friend_list_logic.dart";
import "package:beehive/controllers/user_manager.dart";
import "package:beehive/pages/constants/user_profile_panel/user_profile_panel_view.dart";
import "package:beehive/protos/ws/ws.pb.dart";
import "package:beehive/routes/routes.dart";
import "package:cached_network_image/cached_network_image.dart";
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pinyin/pinyin.dart';  // 导入拼音库

class FriendListPage extends StatelessWidget {
   
  final FriendListLogic friendListLogic = Get.find<FriendListLogic>();

  @override
  Widget build(BuildContext context) {
   
    // 获取好友列表并分组
    List<AZFriendItem> azItems = _buildAzItems();
    // 生成字母索引列表
    List<String> indexTags = _getIndexTags(azItems);
    // 初始化 AZListView
    return AzListView(
      data: azItems,
      itemCount: azItems.length,
      itemBuilder: (context, index) {
   
        final item = azItems[index];
        return Container(
          padding: const EdgeInsets.symmetric(horizontal: 4,vertical: 2),
          margin: EdgeInsets.symmetric(vertical: 1), // 为每个分组项添加间距
          decoration: BoxDecoration(
            color: Colors.white,  // 设置背景颜色
            borderRadius: BorderRadius.circular(8),  // 设置圆角
          ),
          child: ListTile(
            leading: _buildAvatar(
              item.info.friendUser.faceURL,
              friendListLogic.getFriendOnlineStatus(item.info.friendUser.userID),
            ),
            title: Text(
              UserManager.to.userNameMap[item.info.friendUser.userID] ?? item.info.friendUser.nickname,
              overflow: TextOverflow.ellipsis,
              style: TextStyle(
                color: Color(0xFFDBA100),
                fontSize: 18,
                fontFamily: 'Alibaba PuHuiTi 3.0',
                fontWeight: FontWeight.w700,
                height: 0.07,
                letterSpacing: -0.32,
              ),
            ),
            onTap: () {
   
              Get.toNamed(
                Routes.userProfilePanel,
                arguments: {
   
                  'userInfo': item.info.friendUser,
                  'actionType': UserDetailActionType.deleteFriend,
                },
              );
            },
          ),
        );
      },
      // 分组悬停头部
      susItemBuilder: (context, index) {
   
        final tag = azItems[index].getSuspensionTag();
        return Container(
            height: 29,
            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
            clipBehavior: Clip.antiAlias,
            decoration: BoxDecoration(),
            alignment: Alignment.centerLeft,
            child: Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Text(
                  tag,
                  style: TextStyle(
                    color: Color(0xFF787878),
                    fontSize: 14,
                    fontFamily: 'Alibaba PuHuiTi 3.0',
                    fontWeight: FontWeight.w500,
                    height: 0.11,
                    letterSpacing: -0.32,
                  ),
                ),
              ],
            ),
          );
      },
      //字母导航栏与其他组件的间距
      indexBarMargin: EdgeInsets.all(0.0),
      indexBarItemHeight: 18, //字母索引项的高度
      indexHintBuilder: (context, hint) => CircleAvatar(
        child: Text(hint, style: TextStyle(color: Colors.white)),
        backgroundColor: Colors.blue,
      ),
      indexBarData: indexTags,
      //定制字母导航栏
      indexBarOptions: IndexBarOptions(
        needRebuild: true,
        selectItemDecoration: BoxDecoration(
          color: Color(0xFFDBA100),  // 选中字母的背景颜色
          shape: BoxShape.circle,
        ),
      ),
    );
  }

  List<AZFriendItem> _buildAzItems() {
   
    List<AZFriendItem> azItems = friendListLogic.friendList.map((friendInfo) {
   
      String tag = friendInfo.friendUser.nickname;

      // 如果昵称为空,则归为 #
      if (tag.isEmpty) {
   
        tag = "#";
      } else {
   
        // 判断第一个字符是否为字母或汉字
        String firstChar = tag[0];

        // 处理中文昵称,获取拼音首字母
        if (isChinese(firstChar)) {
   
          String pinyin = PinyinHelper.getPinyin(tag)[0].toUpperCase();
          // 如果拼音首字母是非字母字符(如符号),则归为 #
          tag = RegExp(r'[A-Z]').hasMatch(pinyin) ? pinyin : '#';
        } else if (RegExp(r'[A-Za-z]').hasMatch(firstChar)) {
   
          // 对于英文,直接使用首字母
          tag = firstChar.toUpperCase();
        } else {
   
          // 对于其他非字母字符(如符号、数字等),归为 #
          tag = '#';
        }
      }

      return AZFriendItem(
        tag: tag,
        info: friendInfo,
      );
    }).toList();

    // 排序并初始化分组标签
    SuspensionUtil.sortListBySuspensionTag(azItems);
    SuspensionUtil.setShowSuspensionStatus(azItems);

    return azItems;
  }

  List<String> _getIndexTags(List<AZFriendItem> azItems) {
   
    // 提取所有标签,并去重
    Set<String> tagSet = {
   };
    for (var item in azItems) {
   
      tagSet.add(item.getSuspensionTag());
    }
    return tagSet.toList()..sort(); // 对标签进行排序
  }

  // 判断字符是否是中文
  bool isChinese(String char) {
   
    final regExp = RegExp(r'[\u4e00-\u9fa5]');
    return regExp.hasMatch(char);
  }


  // 构建头像组件
  Widget _buildAvatar(String? faceURL, bool onlineStatus) {
   
    Widget avatar;
    const double avatarSize = 44.0;
    if (faceURL != null && faceURL.isNotEmpty) {
   
      if (faceURL.startsWith('http')) {
   
        avatar = CachedNetworkImage(
          imageUrl: faceURL,
          placeholder: (context, url) => CircleAvatar(
            backgroundColor: Colors.grey.shade300,
            radius: avatarSize/2,
          ),
          imageBuilder: (context, imageProvider) => CircleAvatar(
            backgroundColor: Colors.grey.shade300,
            backgroundImage: imageProvider,
            radius: avatarSize/2,
          ),
        );
      } else {
   
        avatar = CircleAvatar(
          backgroundColor: Colors.grey.shade300,
          backgroundImage: AssetImage(faceURL),
          radius: avatarSize/2,
        );
      }
    } else {
   
      avatar = CircleAvatar(
        backgroundImage: const AssetImage(defaultAvatar),
        backgroundColor: Colors.grey.shade300,
        radius: avatarSize/2,
      );
    }

    return Stack(
      children: [
        avatar,
        Positioned(
          right: 0,
          bottom: 0,
          child: Container(
            width: 12,
            height: 12,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: onlineStatus ? Colors.green : Colors.grey,
              border: Border.all(
                color: Colors.white,
                width: 2,
              ),
            ),
          ),
        ),
      ],
    );
  }
}

// AZListView 扩展数据模型
class AZFriendItem extends ISuspensionBean {
   
  final String tag;
  final FriendInfo info;

  AZFriendItem({
   required this.tag, required this.info});

  @override
  String getSuspensionTag() => tag;
}
AI 代码解读
目录
打赏
0
6
7
0
163
分享
相关文章
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
296 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
HarmonyOS Next~鸿蒙应用框架开发实战:Ability Kit与Accessibility Kit深度解析
本书深入解析HarmonyOS应用框架开发,聚焦Ability Kit与Accessibility Kit两大核心组件。Ability Kit通过FA/PA双引擎架构实现跨设备协同,支持分布式能力开发;Accessibility Kit提供无障碍服务构建方案,优化用户体验。内容涵盖设计理念、实践案例、调试优化及未来演进方向,助力开发者打造高效、包容的分布式应用,体现HarmonyOS生态价值。
196 27
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
251 31
【一步步开发AI运动小程序】十九、运动识别中如何解析RGBA帧图片?
本文介绍了如何将相机抽取的RGBA帧图像解析为`.jpg`或`.png`格式,适用于体测、赛事等场景。首先讲解了RGBA图像结构,其为一维数组,每四个元素表示一个像素的颜色与透明度值。接着通过`uni.createOffscreenCanvas()`创建离屏画布以减少绘制干扰,并提供代码实现,将RGBA数据逐像素绘制到画布上生成图片。最后说明了为何不直接使用拍照API及图像转换的调用频率建议,强调应先暂存帧数据,运动结束后再进行转换和上传,以优化性能。
前后端分离开发:如何高效调试API?有工具 vs 无工具全解析
在前后端分离的开发模式中,API 调试的效率直接影响项目的质量和交付速度。通过本文的对比分析,我们可以看到无工具调试模式虽具备灵活性和代码复用能力,但在操作便利性和团队协作上稍显不足。而传统的外部调试工具带来了可视化、高效协作与扩展性,却可能存在工具切换带来的开发链路断层问题。Apipost-Hepler 融合了两者的优势,让开发者无需离开熟悉的 IDEA 环境,就能享受可视化调试工具的强大功能。
109 5
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
117 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
通义灵码AI程序员实战:从零构建Python记账本应用的开发全解析
本文通过开发Python记账本应用的真实案例,展示通义灵码AI程序员2.0的代码生成能力。从需求分析到功能实现、界面升级及测试覆盖,AI程序员展现了需求转化、技术选型、测试驱动和代码可维护性等核心价值。文中详细解析了如何使用Python标准库和tkinter库实现命令行及图形化界面,并生成单元测试用例,确保应用的稳定性和可维护性。尽管AI工具显著提升开发效率,但用户仍需具备编程基础以进行调试和优化。
454 9
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
411 29

推荐镜像

更多
  • DNS
  • AI助理

    你好,我是AI助理

    可以解答问题、推荐解决方案等

    登录插画

    登录以查看您的控制台资源

    管理云资源
    状态一览
    快捷访问