flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// ============================================================
/// CustomScrollView + Sliver 系列演示页
///
/// 一、两种使用方式:
/// 1. 直接运行本页面:runApp(const MaterialApp(home: SliverDemoPage()))
/// 2. 复制 slivers 数组到任意 CustomScrollView 中。
///
/// 二、核心概念:
/// Sliver = "碎片"。CustomScrollView 把多个 sliver 拼成一个
/// 统一的滚动视图(共用一个滚动控制器,整页一起滚)。
///
/// 三、常用 sliver:
/// SliverAppBar : 可折叠/固定的 AppBar(pinned 固定、floating 浮出)
/// SliverToBoxAdapter : 把普通组件(文字/卡片/图片)塞进滚动流
/// SliverGrid.builder : 网格区块(懒加载)
/// SliverList.builder : 列表区块(懒加载)
/// SliverPadding : 给某个 sliver 加内边距
///
/// 四、为什么需要 Sliver(重点):
/// ListView 不能嵌套 ListView/GridView(同向滚动会冲突);
/// Sliver 方案让"AppBar + 网格 + 列表 + 卡片"混排且整页只滚一次。
///
/// 五、和 GridView 的本质区别(重点记忆):
/// GridView 只是 CustomScrollView 的简化套餐:
/// GridView = CustomScrollView + 1 个 SliverGrid。
/// 两者都是"单个滚动 + 懒加载",区别只在混排能力:
/// · 页面只有一种内容(网格/列表)→ GridView / ListView,写起来更简单
/// · 页面要混排多种内容 → 本页这种 CustomScrollView,slivers 拆块拼装
/// 判断口诀:这页是"一个网格"还是"折叠头+网格+长列表"?后者才用 Sliver。
/// ============================================================
class SliverDemoPage extends StatelessWidget {
const SliverDemoPage({super.key});
static const List<Color> _colors = [
Color(0xFF3B82F6), Color(0xFF8E6FE8), Color(0xFFF05252),
Color(0xFFFF9800), Color(0xFF4CAF50), Color(0xFF00BCD4),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
// ① 可折叠 AppBar:下拉展开大图,上滑收起只留标题栏
SliverAppBar(
expandedHeight: 180.h, // 展开时高度
pinned: true, // 滚动时固定在顶部
backgroundColor: Color(0xFF3B82F6),
flexibleSpace: FlexibleSpaceBar(
title: Text('Sliver 系列 Demo'),
centerTitle: true,
background: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF3B82F6), Color(0xFF8E6FE8)],
),
),
),
),
),
// ② 普通组件插进滚动流:SliverToBoxAdapter
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 0),
child: Text(
'网格区块(SliverGrid,懒加载)',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: Color(0xFF333333),
),
),
),
),
// ③ 网格区块
SliverPadding(
padding: EdgeInsets.all(16.w),
sliver: SliverGrid.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 8.w,
crossAxisSpacing: 8.w,
),
itemCount: 12,
itemBuilder: (context, index) => _GridItem(index: index),
),
),
// ④ 区块标题
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.fromLTRB(16.w, 8.h, 16.w, 8.h),
child: Text(
'列表区块(SliverList,懒加载)',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: Color(0xFF333333),
),
),
),
),
// ⑤ 列表区块:50 条,和上面的网格共用同一个滚动
SliverList.builder(
itemCount: 50,
itemBuilder: (context, index) => ListTile(
leading: CircleAvatar(
backgroundColor: _colors[index % _colors.length],
child: Text(
'$index',
style: const TextStyle(color: Colors.white),
),
),
title: Text('第 $index 条'),
subtitle: Text('Sliver 懒加载,滚动到这里才创建'),
trailing: const Icon(Icons.chevron_right),
),
),
],
),
);
}
}
/// 网格项:彩色方块 + 序号
class _GridItem extends StatelessWidget {
const _GridItem({required this.index});
final int index;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: SliverDemoPage._colors[index % SliverDemoPage._colors.length],
borderRadius: BorderRadius.circular(8.r),
),
alignment: Alignment.center,
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
),
);
}
}