当前位置: 首页 > news >正文

Flutter基础(前端教程②-卡片列表)

ListTile 是 Flutter 中专门为列表项设计的标准行组件,它提供了一种简洁的方式来创建带有标题、副标题、图标和按钮的列表项。就像乐高积木一样,ListTile 帮你快速搭建出常见的列表布局。

 为什么需要 ListTile?

想象你要创建一个联系人列表,每个联系人需要显示:

  • 左侧头像
  • 中间名字(主标题)
  • 下方电话号码(副标题)
  • 右侧操作按钮

手动用 ColumnRow 和 Padding 组合实现会很繁琐,而 ListTile 把这些功能集成在一起,一行代码搞定!

ListTile 的核心属性:

ListTile(leading: Icon(Icons.person),        // 左侧图标/图片title: Text('联系人姓名'),           // 主标题(粗体)subtitle: Text('电话号码'),          // 副标题(灰色小字)trailing: Icon(Icons.arrow_forward), // 右侧图标/按钮onTap: () {},                       // 点击事件
);

好的!Card 是 Flutter 中专门用于创建卡片式布局的组件,它提供了默认的圆角、阴影和内边距,让你轻松实现现代应用中常见的卡片设计。

Card 的最简形式:

Card(child: Text('这是一个简单的卡片'),
);

效果:一个带有圆角和轻微阴影的白色矩形区域。

常用属性

Card(elevation: 8,           // 阴影深度(默认2)color: Colors.blue,    // 卡片背景色shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12), // 圆角半径),margin: EdgeInsets.all(16), // 卡片外边距child: Text('自定义样式的卡片'),
);

卡片

Card(child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Image.network('https://example.com/news.jpg'), // 卡片顶部图片Padding(padding: EdgeInsets.all(12),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Text('这是新闻标题',style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),SizedBox(height: 8),Text('这是新闻内容摘要...'),],),),],),
);  

下面是这个代码对应的卡片视觉示意图(简化版):

+----------------------------------------+
|                                        |
|  [新闻图片]                            |  ← Image.network(顶部占满宽度)
|  (https://example.com/news.jpg)        |
|                                        |
+----------------------------------------+
|  这是新闻标题                           |  ← Text(加粗、18号字体)
|                                        |
|  这是新闻内容摘要...                    |  ← Text(普通文本)
|                                        |  (上下左右内边距12,与标题间距8)
+----------------------------------------+

Flutter 中创建列表的 3 种方式

方式 1:直接用 ListView

适合少量固定数量的列表项:

ListView(children: [Text('第一项'),Text('第二项'),Text('第三项'),],
)
方式 2:用 ListView.builder 动态生成

适合大量数据(自动复用组件,性能更好):

ListView.builder(itemCount: 100, // 列表项数量itemBuilder: (context, index) {return Text('第 $index 项');},
)
方式 3:用 ListTile 快速创建标准列表项

适合联系人、设置项等标准行布局:

ListView(children: [ListTile(leading: Icon(Icons.person),title: Text('联系人1'),subtitle: Text('电话:13800000000'),),ListTile(leading: Icon(Icons.person),title: Text('联系人2'),subtitle: Text('电话:13900000000'),),],
)

下面是一个类似微信聊天列表界面的简化实现,包含头像、名称、消息预览和时间:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return MaterialApp(theme: ThemeData(primarySwatch: Colors.green),home: const WeChatHomePage(),);}
}class WeChatHomePage extends StatelessWidget {const WeChatHomePage({Key? key}) : super(key: key);// 模拟聊天数据List<Map<String, dynamic>> getChatData() {return [{'name': '张三','avatar': 'https://picsum.photos/100/100?random=1','message': '下午一起吃饭吗?','time': DateTime.now().subtract(const Duration(minutes: 5)),'unread': 2,},{'name': '李四','avatar': 'https://picsum.photos/100/100?random=2','message': '好的,我稍后回复你','time': DateTime.now().subtract(const Duration(hours: 1)),'unread': 0,},{'name': '工作群','avatar': 'https://picsum.photos/100/100?random=3','message': '王五:明天上午10点开会','time': DateTime.now().subtract(const Duration(hours: 3)),'unread': 5,},{'name': '妈妈','avatar': 'https://picsum.photos/100/100?random=4','message': '记得带伞,今天下雨','time': DateTime.now().subtract(const Duration(days: 1)),'unread': 0,},{'name': '同事A','avatar': 'https://picsum.photos/100/100?random=5','message': '项目文档已发送,请查收','time': DateTime.now().subtract(const Duration(days: 1)),'unread': 1,},];}@overrideWidget build(BuildContext context) {final chatData = getChatData();return Scaffold(appBar: AppBar(title: const Text('微信'),actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {}),IconButton(icon: const Icon(Icons.add), onPressed: () {}),],),body: ListView.builder(itemCount: chatData.length,itemBuilder: (context, index) {final chat = chatData[index];final formattedTime = _formatTime(chat['time']);return Column(children: [// 分隔线(除了第一个)if (index > 0) const Divider(height: 0),// 聊天项ListTile(leading: CircleAvatar(backgroundImage: NetworkImage(chat['avatar']),radius: 28,),title: Text(chat['name'],style: TextStyle(fontWeight: chat['unread'] > 0 ? FontWeight.bold : FontWeight.normal,),),subtitle: Text(chat['message'],maxLines: 1,overflow: TextOverflow.ellipsis,style: TextStyle(color: Colors.grey[600],),),trailing: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.end,children: [// 时间Text(formattedTime,style: TextStyle(fontSize: 12,color: Colors.grey[500],),),// 未读数(如果有)if (chat['unread'] > 0)Container(margin: const EdgeInsets.only(top: 4),padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),decoration: BoxDecoration(color: Colors.red,borderRadius: BorderRadius.circular(10),),child: Text(chat['unread'].toString(),style: const TextStyle(color: Colors.white, fontSize: 12),),),],),onTap: () {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('打开与 ${chat['name']} 的聊天')));},),],);},),);}// 格式化时间(根据是否今天显示不同格式)String _formatTime(DateTime time) {final now = DateTime.now();final today = DateTime(now.year, now.month, now.day);final yesterday = today.subtract(const Duration(days: 1));if (DateTime(time.year, time.month, time.day).isAtSameMomentAs(today)) {// 今天:显示时:分return DateFormat('HH:mm').format(time);} else if (DateTime(time.year, time.month, time.day).isAtSameMomentAs(yesterday)) {// 昨天:显示"昨天"return '昨天';} else {// 其他:显示月-日return DateFormat('MM-dd').format(time);}}
}

http://www.lryc.cn/news/582958.html

相关文章:

  • 【牛客刷题】小红的v三元组
  • 从单体到微服务:Spring Cloud 开篇与微服务设计
  • 音频主动降噪技术
  • 暑假算法日记第四天
  • Spring AI:检索增强生成(RAG)
  • 工作中的思考
  • Java教程:【程序调试技巧】入门
  • 项目Win系统下可正常获取Header字段,但是到了linux、docker部署后无法获取
  • 数据湖技术之Iceberg-03 Iceberg整合Flink 实时写入与增量读取
  • 【HarmonyOS】鸿蒙端云一体化开发入门详解 (一)
  • 深度剖析 Linux ip neigh:邻居表项的查看与添加实践
  • RabbitMQ第二章(RocketMQ的五大工作模式)
  • 二进制安全-汇编语言-04-第一个程序
  • 为什么elementui的<el-table-column label=“名称“ prop=“name“ label不用写成:label
  • Docker快速部署Hive服务
  • C++ 遍历可变参数的几种方法
  • 零基础|宝塔面板|frp内网穿透|esp32cam远程访问|微信小程序
  • 链表算法之【移除链表元素】
  • 【深度学习新浪潮】什么是上下文长度?
  • C++异步编程入门
  • 猿人学js逆向比赛第一届第十五题
  • Java面试基础:概念
  • 部署并运行Vim/Vmamba在ImageNet上的训练与测试
  • JavaScript之数组方法详解
  • (C++)list列表相关基础用法(C++教程)(STL库基础教程)
  • HTTP/3.x协议详解:基于QUIC的下一代Web传输协议
  • 音频被动降噪技术
  • nng库使用
  • Android Handler机制与底层原理详解
  • Java 阻塞队列:7种类型全解析