进阶实战 Flutter for OpenHarmony:高性能列表虚拟化系统 - 大数据量渲染优化实现

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


一、列表虚拟化系统架构深度解析

在现代移动应用中,列表是最常见的 UI 组件之一。当数据量达到成千上万条时,如何保证列表的流畅滚动成为关键问题。Flutter 通过虚拟化技术,只渲染可见区域的元素,实现了大数据量列表的高性能渲染。理解这套架构的底层原理,是构建高性能列表系统的基础。

📱 1.1 Flutter 列表虚拟化架构

Flutter 的列表虚拟化系统由多个核心层次组成,每一层都有其特定的职责:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      应用层 (Application Layer)                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  ListView, GridView, CustomScrollView...                │    │
│  └─────────────────────────────────────────────────────────┘    │
│                              │                                   │
│                              ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              Sliver层 (Sliver Layer)                     │    │
│  │  SliverList, SliverGrid, SliverChildBuilderDelegate...  │    │
│  └─────────────────────────────────────────────────────────┘    │
│                              │                                   │
│                              ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              视口层 (Viewport Layer)                     │    │
│  │  Viewport, RenderViewport, Scrollable...                │    │
│  └─────────────────────────────────────────────────────────┘    │
│                              │                                   │
│                              ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              渲染层 (Render Layer)                       │    │
│  │  RenderSliver, RenderBox, RenderViewport...             │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

🔬 1.2 列表虚拟化核心组件详解

Flutter 列表虚拟化系统的核心组件包括以下几个部分:

Viewport(视口)

Viewport 是虚拟化的核心,只渲染可见区域的子组件。

dart 复制代码
Viewport(
  offset: ScrollController(),
  slivers: [
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) => ListTile(title: Text('Item $index')),
        childCount: 10000,
      ),
    ),
  ],
)

Sliver(切片)

Sliver 是可滚动区域的基本单位,可以灵活组合各种滚动效果。

dart 复制代码
CustomScrollView(
  slivers: [
    SliverAppBar(),
    SliverList(),
    SliverGrid(),
    SliverPersistentHeader(),
  ],
)

Scrollable(可滚动)

Scrollable 处理滚动手势和物理效果。

dart 复制代码
Scrollable(
  viewportBuilder: (context, offset) {
    return Viewport(offset: offset, slivers: [...]);
  },
)

🎯 1.3 虚拟化工作原理

列表虚拟化的核心原理是只创建和渲染可见区域的 Widget:

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    列表虚拟化工作原理                         │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  缓存区域 (CacheExtent)                              │    │
│  │  预加载即将可见的元素                                 │    │
│  └─────────────────────────────────────────────────────┘    │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  可见区域 (Visible Area)                             │    │
│  │  ████████████████████████████████████████████████   │    │
│  │  │ Item 3  │ Item 4  │ Item 5  │ Item 6  │ Item 7  │   │    │
│  │  ████████████████████████████████████████████████   │    │
│  │  实际渲染的 Widget                                   │    │
│  └─────────────────────────────────────────────────────┘    │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  虚拟区域 (Virtual Area)                             │    │
│  │  Item 0, 1, 2... (未渲染)                           │    │
│  │  Item 8, 9, 10... (未渲染)                          │    │
│  │  只保留数据引用,不创建 Widget                        │    │
│  └─────────────────────────────────────────────────────┘    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

列表类型对比:

类型 特点 适用场景
ListView 简单线性列表 基础列表
ListView.builder 懒加载虚拟化 大数据量列表
ListView.separated 带分隔符的列表 分组列表
GridView 网格布局 图片画廊
CustomScrollView 自定义 Sliver 组合 复杂滚动效果
SliverList 灵活的列表 Sliver 组合滚动
SliverGrid 灵活的网格 Sliver 组合网格

二、基础虚拟化列表实现

基础虚拟化列表包括 ListView.builder、GridView.builder 和带缓存策略的列表。这些是构建高性能列表系统的基础。

👆 2.1 ListView.builder 基础实现

ListView.builder 是最常用的虚拟化列表,通过 builder 模式按需创建 Widget。

dart 复制代码
import 'package:flutter/material.dart';

/// ListView.builder 基础示例
class BasicListViewDemo extends StatelessWidget {
  const BasicListViewDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ListView.builder 基础')),
      body: ListView.builder(
        itemCount: 10000,
        cacheExtent: 500,
        itemBuilder: (context, index) {
          return ListTile(
            leading: CircleAvatar(
              child: Text('${index + 1}'),
            ),
            title: Text('列表项 ${index + 1}'),
            subtitle: Text('这是第 ${index + 1} 个列表项的描述'),
            trailing: const Icon(Icons.chevron_right),
            onTap: () {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('点击了第 ${index + 1} 项')),
              );
            },
          );
        },
      ),
    );
  }
}

🔄 2.2 高级 ListView 配置

高级 ListView 配置包括控制器、物理效果、缓存区域等参数优化。

dart 复制代码
/// 高级 ListView 配置示例
class AdvancedListViewDemo extends StatefulWidget {
  const AdvancedListViewDemo({super.key});

  @override
  State<AdvancedListViewDemo> createState() => _AdvancedListViewDemoState();
}

class _AdvancedListViewDemoState extends State<AdvancedListViewDemo> {
  final ScrollController _scrollController = ScrollController();
  final List<String> _items = List.generate(100, (index) => 'Item $index');
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.removeListener(_onScroll);
    _scrollController.dispose();
    super.dispose();
  }

  void _onScroll() {
    if (_scrollController.position.pixels >=
        _scrollController.position.maxScrollExtent - 200) {
      _loadMore();
    }
  }

  Future<void> _loadMore() async {
    if (_isLoading) return;
    setState(() => _isLoading = true);
  
    await Future.delayed(const Duration(seconds: 1));
  
    setState(() {
      final startIndex = _items.length;
      for (int i = 0; i < 20; i++) {
        _items.add('Item ${startIndex + i}');
      }
      _isLoading = false;
    });
  }

  Future<void> _onRefresh() async {
    await Future.delayed(const Duration(seconds: 1));
    setState(() {
      _items.clear();
      _items.addAll(List.generate(100, (index) => 'Item $index (刷新)'));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('高级 ListView 配置')),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          controller: _scrollController,
          physics: const BouncingScrollPhysics(),
          cacheExtent: 1000,
          itemCount: _items.length + 1,
          itemBuilder: (context, index) {
            if (index == _items.length) {
              return _buildLoadingIndicator();
            }
            return _buildListItem(index);
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _scrollController.animateTo(
            0,
            duration: const Duration(milliseconds: 500),
            curve: Curves.easeInOut,
          );
        },
        child: const Icon(Icons.arrow_upward),
      ),
    );
  }

  Widget _buildListItem(int index) {
    return Dismissible(
      key: Key(_items[index]),
      background: Container(
        color: Colors.red,
        alignment: Alignment.centerRight,
        padding: const EdgeInsets.only(right: 20),
        child: const Icon(Icons.delete, color: Colors.white),
      ),
      direction: DismissDirection.endToStart,
      onDismissed: (direction) {
        setState(() {
          _items.removeAt(index);
        });
      },
      child: Card(
        margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
        child: ListTile(
          leading: Hero(
            tag: 'item-$index',
            child: CircleAvatar(
              backgroundColor: Colors.primaries[index % Colors.primaries.length],
              child: Text('${index + 1}'),
            ),
          ),
          title: Text(_items[index]),
          subtitle: Text('索引: $index'),
          trailing: const Icon(Icons.chevron_right),
        ),
      ),
    );
  }

  Widget _buildLoadingIndicator() {
    return Container(
      padding: const EdgeInsets.all(16),
      alignment: Alignment.center,
      child: _isLoading
          ? const CircularProgressIndicator()
          : const Text('上拉加载更多'),
    );
  }
}

🌊 2.3 GridView 虚拟化实现

GridView 通过网格布局实现高效的图片画廊和数据展示。

dart 复制代码
/// GridView 虚拟化示例
class GridViewDemo extends StatelessWidget {
  const GridViewDemo({super.key});

  List<Color> get _colors => List.generate(
    100,
    (index) => Color.fromRGBO(
      (index * 25) % 256,
      (index * 50) % 256,
      (index * 75) % 256,
      1.0,
    ),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('GridView 虚拟化')),
      body: GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          mainAxisSpacing: 4,
          crossAxisSpacing: 4,
          childAspectRatio: 1.0,
        ),
        itemCount: 100,
        cacheExtent: 500,
        itemBuilder: (context, index) {
          return GestureDetector(
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => GridDetailPage(
                    index: index,
                    color: _colors[index],
                  ),
                ),
              );
            },
            child: Hero(
              tag: 'grid-item-$index',
              child: Container(
                color: _colors[index],
                child: Center(
                  child: Text(
                    '${index + 1}',
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class GridDetailPage extends StatelessWidget {
  final int index;
  final Color color;

  const GridDetailPage({
    super.key,
    required this.index,
    required this.color,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: color,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: Text('详情 ${index + 1}'),
      ),
      body: Center(
        child: Hero(
          tag: 'grid-item-$index',
          child: Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              color: color,
              borderRadius: BorderRadius.circular(20),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.3),
                  blurRadius: 20,
                  offset: const Offset(0, 10),
                ),
              ],
            ),
            child: Center(
              child: Text(
                '${index + 1}',
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 48,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

三、Sliver 家族组件深度实现

Sliver 家族是 Flutter 滚动系统的核心,提供了灵活的组合滚动能力。

📊 3.1 CustomScrollView 组合滚动

CustomScrollView 允许组合多个 Sliver 实现复杂的滚动效果。

dart 复制代码
/// CustomScrollView 组合滚动示例
class CustomScrollViewDemo extends StatelessWidget {
  const CustomScrollViewDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          _buildSliverAppBar(),
          _buildSliverPersistentHeader(),
          _buildSliverGrid(),
          _buildSliverList(),
          _buildSliverFillRemaining(),
        ],
      ),
    );
  }

  Widget _buildSliverAppBar() {
    return SliverAppBar(
      expandedHeight: 200,
      floating: false,
      pinned: true,
      snap: false,
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('CustomScrollView'),
        background: Container(
          decoration: const BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [Colors.blue, Colors.purple],
            ),
          ),
          child: const Center(
            child: Icon(
              Icons.list_alt,
              size: 80,
              color: Colors.white54,
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildSliverPersistentHeader() {
    return SliverPersistentHeader(
      pinned: true,
      delegate: _SectionHeaderDelegate(
        title: '网格区域',
        color: Colors.blue.shade100,
      ),
    );
  }

  Widget _buildSliverGrid() {
    return SliverGrid(
      gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 150,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 1.0,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Container(
            margin: const EdgeInsets.all(4),
            decoration: BoxDecoration(
              color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.3),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Center(
              child: Text(
                'Grid $index',
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          );
        },
        childCount: 12,
      ),
    );
  }

  Widget _buildSliverList() {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Card(
            margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
            child: ListTile(
              leading: CircleAvatar(
                child: Text('$index'),
              ),
              title: Text('列表项 $index'),
              subtitle: Text('这是第 $index 个列表项'),
              trailing: const Icon(Icons.chevron_right),
            ),
          );
        },
        childCount: 20,
      ),
    );
  }

  Widget _buildSliverFillRemaining() {
    return SliverFillRemaining(
      hasScrollBody: false,
      child: Container(
        color: Colors.grey.shade200,
        padding: const EdgeInsets.all(32),
        child: const Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.info_outline, size: 48, color: Colors.grey),
            SizedBox(height: 16),
            Text(
              '列表底部区域',
              style: TextStyle(fontSize: 18, color: Colors.grey),
            ),
          ],
        ),
      ),
    );
  }
}

class _SectionHeaderDelegate extends SliverPersistentHeaderDelegate {
  final String title;
  final Color color;

  _SectionHeaderDelegate({required this.title, required this.color});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      color: color,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      child: Align(
        alignment: Alignment.centerLeft,
        child: Text(
          title,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }

  @override
  double get maxExtent => 50;

  @override
  double get minExtent => 50;

  @override
  bool shouldRebuild(covariant _SectionHeaderDelegate oldDelegate) {
    return title != oldDelegate.title || color != oldDelegate.color;
  }
}

🎨 3.2 SliverAnimatedList 动画列表

SliverAnimatedList 支持列表项的增删动画效果。

dart 复制代码
/// SliverAnimatedList 动画列表示例
class SliverAnimatedListDemo extends StatefulWidget {
  const SliverAnimatedListDemo({super.key});

  @override
  State<SliverAnimatedListDemo> createState() => _SliverAnimatedListDemoState();
}

class _SliverAnimatedListDemoState extends State<SliverAnimatedListDemo> {
  final GlobalKey<SliverAnimatedListState> _listKey = GlobalKey();
  final List<String> _items = List.generate(10, (index) => 'Item $index');
  int _counter = 10;

  void _addItem() {
    final index = _items.length;
    _items.insert(index, 'Item $_counter');
    _listKey.currentState?.insertItem(index);
    _counter++;
  }

  void _removeItem(int index) {
    _listKey.currentState?.removeItem(
      index,
      (context, animation) => _buildRemovedItem(_items[index], animation),
    );
    _items.removeAt(index);
  }

  Widget _buildRemovedItem(String item, Animation<double> animation) {
    return SizeTransition(
      sizeFactor: animation,
      child: Card(
        margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
        color: Colors.red.shade100,
        child: ListTile(
          title: Text(item),
          trailing: const Icon(Icons.delete, color: Colors.red),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SliverAnimatedList')),
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            pinned: true,
            title: const Text('动画列表'),
            actions: [
              IconButton(
                icon: const Icon(Icons.add),
                onPressed: _addItem,
              ),
            ],
          ),
          SliverAnimatedList(
            key: _listKey,
            initialItemCount: _items.length,
            itemBuilder: (context, index, animation) {
              return _buildItem(_items[index], index, animation);
            },
          ),
        ],
      ),
    );
  }

  Widget _buildItem(String item, int index, Animation<double> animation) {
    return SlideTransition(
      position: Tween<Offset>(
        begin: const Offset(1, 0),
        end: Offset.zero,
      ).animate(CurvedAnimation(
        parent: animation,
        curve: Curves.easeOut,
      )),
      child: SizeTransition(
        sizeFactor: animation,
        child: Card(
          margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
          child: ListTile(
            leading: CircleAvatar(
              child: Text('$index'),
            ),
            title: Text(item),
            subtitle: Text('索引: $index'),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () => _removeItem(index),
            ),
          ),
        ),
      ),
    );
  }
}

🔄 3.3 SliverToBoxAdapter 与 SliverPadding

SliverToBoxAdapter 将普通 Widget 转换为 Sliver,SliverPadding 为 Sliver 添加内边距。

dart 复制代码
/// SliverToBoxAdapter 与 SliverPadding 示例
class SliverAdapterDemo extends StatelessWidget {
  const SliverAdapterDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            expandedHeight: 150,
            pinned: true,
            flexibleSpace: FlexibleSpaceBar(
              title: const Text('Sliver Adapter'),
              background: Container(
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [Colors.teal, Colors.cyan],
                  ),
                ),
              ),
            ),
          ),
          SliverPadding(
            padding: const EdgeInsets.all(16),
            sliver: SliverToBoxAdapter(
              child: Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'SliverToBoxAdapter',
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text(
                        '将普通 Widget 转换为 Sliver,可以在 CustomScrollView 中使用任何 Widget。',
                        style: TextStyle(color: Colors.grey[600]),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
          SliverPadding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            sliver: SliverToBoxAdapter(
              child: Container(
                height: 100,
                decoration: BoxDecoration(
                  color: Colors.blue.shade100,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: const Center(
                  child: Text('横幅广告区域'),
                ),
              ),
            ),
          ),
          SliverPadding(
            padding: const EdgeInsets.all(16),
            sliver: SliverGrid(
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                mainAxisSpacing: 8,
                crossAxisSpacing: 8,
                childAspectRatio: 1.5,
              ),
              delegate: SliverChildBuilderDelegate(
                (context, index) {
                  return Container(
                    decoration: BoxDecoration(
                      color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.2),
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Center(child: Text('卡片 $index')),
                  );
                },
                childCount: 6,
              ),
            ),
          ),
          SliverPadding(
            padding: const EdgeInsets.all(16),
            sliver: SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) {
                  return Card(
                    child: ListTile(
                      leading: CircleAvatar(child: Text('$index')),
                      title: Text('列表项 $index'),
                    ),
                  );
                },
                childCount: 10,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

四、自定义 Sliver 组件实现

自定义 Sliver 组件可以实现独特的滚动效果和布局。

🎯 4.1 自定义 SliverPersistentHeader

自定义 SliverPersistentHeader 实现可折叠的头部效果。

dart 复制代码
/// 自定义 SliverPersistentHeader 示例
class CustomSliverHeaderDemo extends StatelessWidget {
  const CustomSliverHeaderDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverPersistentHeader(
            pinned: true,
            delegate: _CustomHeaderDelegate(
              minHeight: 80,
              maxHeight: 250,
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return ListTile(
                  title: Text('列表项 $index'),
                  subtitle: Text('这是第 $index 个列表项'),
                );
              },
              childCount: 50,
            ),
          ),
        ],
      ),
    );
  }
}

class _CustomHeaderDelegate extends SliverPersistentHeaderDelegate {
  final double minHeight;
  final double maxHeight;

  _CustomHeaderDelegate({
    required this.minHeight,
    required this.maxHeight,
  });

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    final progress = shrinkOffset / (maxHeight - minHeight);
    final opacity = 1.0 - progress;
    final scale = 1.0 - progress * 0.3;

    return Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [
            Colors.indigo,
            Colors.purple.withOpacity(opacity),
          ],
        ),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.2 * progress),
            blurRadius: 10,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Stack(
        children: [
          Positioned(
            left: 16,
            bottom: 16,
            child: Opacity(
              opacity: opacity,
              child: Transform.scale(
                scale: scale,
                alignment: Alignment.bottomLeft,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const Text(
                      '自定义头部',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 28,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 8),
                    Text(
                      '折叠进度: ${(progress * 100).toStringAsFixed(0)}%',
                      style: TextStyle(
                        color: Colors.white.withOpacity(opacity),
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          Positioned(
            right: 16,
            bottom: 16,
            child: Opacity(
              opacity: progress,
              child: const Text(
                '已折叠',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  double get maxExtent => maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  bool shouldRebuild(covariant _CustomHeaderDelegate oldDelegate) {
    return minHeight != oldDelegate.minHeight ||
           maxHeight != oldDelegate.maxHeight;
  }
}

📐 4.2 自定义 SliverChildDelegate

自定义 SliverChildDelegate 实现更灵活的列表项构建策略。

dart 复制代码
/// 自定义 SliverChildDelegate 示例
class CustomSliverDelegateDemo extends StatelessWidget {
  const CustomSliverDelegateDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('自定义 SliverChildDelegate')),
      body: CustomScrollView(
        slivers: [
          SliverList(
            delegate: _PagedChildDelegate(
              itemCount: 1000,
              pageSize: 20,
              itemBuilder: (context, index) {
                return ListTile(
                  leading: CircleAvatar(child: Text('$index')),
                  title: Text('分页加载项 $index'),
                  subtitle: Text('页码: ${(index / 20).floor() + 1}'),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

class _PagedChildDelegate extends SliverChildDelegate {
  final int itemCount;
  final int pageSize;
  final Widget Function(BuildContext, int) itemBuilder;

  _PagedChildDelegate({
    required this.itemCount,
    required this.pageSize,
    required this.itemBuilder,
  });

  @override
  Widget? build(BuildContext context, int index) {
    if (index < 0 || index >= itemCount) return null;
    return itemBuilder(context, index);
  }

  @override
  int get estimatedChildCount => itemCount;

  @override
  double estimateMaxScrollOffset(
    int firstIndex,
    int lastIndex,
    double leadingScrollOffset,
    double trailingScrollOffset,
  ) {
    return itemCount * (trailingScrollOffset - leadingScrollOffset) / (lastIndex - firstIndex + 1);
  }

  @override
  int findIndexForKey(Key key) {
    if (key is ValueKey<int>) {
      return key.value;
    }
    return null!;
  }
}

🔄 4.3 自定义 RenderSliver

通过自定义 RenderSliver 实现完全自定义的滚动布局效果。

dart 复制代码
import 'dart:math' as math;
import 'package:flutter/rendering.dart';

/// 自定义 RenderSliver 示例
class CustomRenderSliverDemo extends StatelessWidget {
  const CustomRenderSliverDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('自定义 RenderSliver')),
      body: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Container(
              height: 100,
              color: Colors.blue.shade100,
              child: const Center(child: Text('顶部区域')),
            ),
          ),
          const SpiralSliver(
            itemCount: 30,
            itemSize: 60,
          ),
          SliverToBoxAdapter(
            child: Container(
              height: 100,
              color: Colors.green.shade100,
              child: const Center(child: Text('底部区域')),
            ),
          ),
        ],
      ),
    );
  }
}

/// 螺旋布局 Sliver
class SpiralSliver extends LeafRenderObjectWidget {
  final int itemCount;
  final double itemSize;

  const SpiralSliver({
    super.key,
    required this.itemCount,
    this.itemSize = 50,
  });

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderSpiralSliver(
      itemCount: itemCount,
      itemSize: itemSize,
    );
  }

  @override
  void updateRenderObject(BuildContext context, covariant RenderSpiralSliver renderObject) {
    renderObject
      ..itemCount = itemCount
      ..itemSize = itemSize;
  }
}

class RenderSpiralSliver extends RenderSliver {
  int _itemCount;
  double _itemSize;

  RenderSpiralSliver({
    required int itemCount,
    required double itemSize,
  })  : _itemCount = itemCount,
        _itemSize = itemSize;

  int get itemCount => _itemCount;
  set itemCount(int value) {
    if (_itemCount != value) {
      _itemCount = value;
      markNeedsLayout();
    }
  }

  double get itemSize => _itemSize;
  set itemSize(double value) {
    if (_itemSize != value) {
      _itemSize = value;
      markNeedsLayout();
    }
  }

  @override
  void performLayout() {
    final double totalHeight = _itemCount * _itemSize * 0.5;
  
    geometry = SliverGeometry(
      scrollExtent: totalHeight,
      paintExtent: math.min(totalHeight, constraints.remainingPaintExtent),
      maxPaintExtent: totalHeight,
      hasVisualOverflow: totalHeight > constraints.remainingPaintExtent,
    );
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;
    canvas.save();
    canvas.translate(offset.dx, offset.dy);

    final visibleHeight = geometry!.paintExtent;
  
    for (int i = 0; i < _itemCount; i++) {
      final y = i * _itemSize * 0.5;
    
      if (y + _itemSize < 0 || y > visibleHeight) continue;
    
      final angle = i * 0.3;
      final x = 150 + 50 * math.sin(angle);
    
      final paint = Paint()
        ..color = Colors.primaries[i % Colors.primaries.length]
        ..style = PaintingStyle.fill;
    
      canvas.drawCircle(
        Offset(x, y + _itemSize / 2),
        _itemSize / 3,
        paint,
      );
    }

    canvas.restore();
  }
}

五、大数据量优化策略

大数据量场景下需要综合运用多种优化策略来保证性能。

📊 5.1 列表项复用与缓存

通过 KeepAlive 和 AutomaticKeepAlive 实现列表项的状态保持。

dart 复制代码
/// 列表项复用与缓存示例
class ListCacheDemo extends StatelessWidget {
  const ListCacheDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('列表项缓存')),
      body: ListView.builder(
        itemCount: 100,
        cacheExtent: 500,
        addAutomaticKeepAlives: true,
        addRepaintBoundaries: true,
        itemBuilder: (context, index) {
          return _CachedListItem(index: index);
        },
      ),
    );
  }
}

class _CachedListItem extends StatefulWidget {
  final int index;

  const _CachedListItem({required this.index});

  @override
  State<_CachedListItem> createState() => _CachedListItemState();
}

class _CachedListItemState extends State<_CachedListItem>
    with AutomaticKeepAliveClientMixin {
  int _tapCount = 0;

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
  
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: ListTile(
        leading: CircleAvatar(
          child: Text('${widget.index}'),
        ),
        title: Text('列表项 ${widget.index}'),
        subtitle: Text('点击次数: $_tapCount'),
        trailing: ElevatedButton(
          onPressed: () {
            setState(() {
              _tapCount++;
            });
          },
          child: const Text('点击'),
        ),
      ),
    );
  }
}

🔄 5.2 分页加载实现

分页加载是处理大数据量的核心策略。

dart 复制代码
/// 分页加载示例
class PaginationDemo extends StatefulWidget {
  const PaginationDemo({super.key});

  @override
  State<PaginationDemo> createState() => _PaginationDemoState();
}

class _PaginationDemoState extends State<PaginationDemo> {
  final List<DataItem> _items = [];
  final int _pageSize = 20;
  int _currentPage = 0;
  bool _isLoading = false;
  bool _hasMore = true;
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _loadFirstPage();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  Future<void> _loadFirstPage() async {
    await _loadPage();
  }

  void _onScroll() {
    if (_scrollController.position.pixels >=
        _scrollController.position.maxScrollExtent - 200) {
      _loadMore();
    }
  }

  Future<void> _loadPage() async {
    if (_isLoading || !_hasMore) return;

    setState(() => _isLoading = true);

    await Future.delayed(const Duration(milliseconds: 500));

    final newItems = await _fetchItems(_currentPage, _pageSize);
  
    setState(() {
      _items.addAll(newItems);
      _currentPage++;
      _hasMore = newItems.length == _pageSize;
      _isLoading = false;
    });
  }

  Future<void> _loadMore() async {
    await _loadPage();
  }

  Future<List<DataItem>> _fetchItems(int page, int size) async {
    return List.generate(size, (index) {
      final globalIndex = page * size + index;
      return DataItem(
        id: globalIndex,
        title: 'Item $globalIndex',
        subtitle: 'Page ${page + 1}',
      );
    });
  }

  Future<void> _onRefresh() async {
    setState(() {
      _items.clear();
      _currentPage = 0;
      _hasMore = true;
    });
    await _loadPage();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('分页加载')),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          controller: _scrollController,
          itemCount: _items.length + (_hasMore ? 1 : 0),
          itemBuilder: (context, index) {
            if (index == _items.length) {
              return _buildLoadingFooter();
            }
            return _buildItem(_items[index]);
          },
        ),
      ),
    );
  }

  Widget _buildItem(DataItem item) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: ListTile(
        leading: CircleAvatar(child: Text('${item.id}')),
        title: Text(item.title),
        subtitle: Text(item.subtitle),
      ),
    );
  }

  Widget _buildLoadingFooter() {
    return Container(
      padding: const EdgeInsets.all(16),
      alignment: Alignment.center,
      child: _isLoading
          ? const CircularProgressIndicator()
          : const Text('没有更多数据'),
    );
  }
}

class DataItem {
  final int id;
  final String title;
  final String subtitle;

  DataItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
}

🎯 5.3 虚拟化性能监控

实现虚拟化列表的性能监控和优化指标。

dart 复制代码
/// 虚拟化性能监控示例
class PerformanceMonitorDemo extends StatefulWidget {
  const PerformanceMonitorDemo({super.key});

  @override
  State<PerformanceMonitorDemo> createState() => _PerformanceMonitorDemoState();
}

class _PerformanceMonitorDemoState extends State<PerformanceMonitorDemo> {
  final ScrollController _scrollController = ScrollController();
  int _visibleItemCount = 0;
  int _totalItemCount = 10000;
  double _scrollOffset = 0;
  int _buildCount = 0;
  DateTime? _lastBuildTime;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  void _onScroll() {
    setState(() {
      _scrollOffset = _scrollController.offset;
    });
  }

  void _onBuild() {
    final now = DateTime.now();
    if (_lastBuildTime != null) {
      final diff = now.difference(_lastBuildTime!).inMilliseconds;
      if (diff < 16) {
        _buildCount++;
      }
    }
    _lastBuildTime = now;
  }

  void _updateVisibleCount(bool visible) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        setState(() {
          if (visible) {
            _visibleItemCount++;
          } else {
            _visibleItemCount = _visibleItemCount > 0 
                ? _visibleItemCount - 1 
                : 0;
          }
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('性能监控')),
      body: Column(
        children: [
          _buildPerformancePanel(),
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              itemCount: _totalItemCount,
              cacheExtent: 500,
              itemBuilder: (context, index) {
                _onBuild();
                return _PerformanceMonitoredItem(
                  index: index,
                  onVisible: _updateVisibleCount,
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPerformancePanel() {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.blue.shade50,
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            blurRadius: 4,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildMetric('总项数', '$_totalItemCount'),
              _buildMetric('可见项', '$_visibleItemCount'),
              _buildMetric('滚动位置', '${_scrollOffset.toStringAsFixed(0)}px'),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildMetric('构建次数', '$_buildCount'),
              _buildMetric('帧率', _buildCount < 60 ? '60fps' : '低'),
              _buildMetric('内存', '虚拟化'),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildMetric(String label, String value) {
    return Column(
      children: [
        Text(
          value,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Colors.blue,
          ),
        ),
        Text(
          label,
          style: TextStyle(
            fontSize: 12,
            color: Colors.grey[600],
          ),
        ),
      ],
    );
  }
}

class _PerformanceMonitoredItem extends StatefulWidget {
  final int index;
  final Function(bool) onVisible;

  const _PerformanceMonitoredItem({
    required this.index,
    required this.onVisible,
  });

  @override
  State<_PerformanceMonitoredItem> createState() => 
      _PerformanceMonitoredItemState();
}

class _PerformanceMonitoredItemState 
    extends State<_PerformanceMonitoredItem> {
  @override
  void initState() {
    super.initState();
    widget.onVisible(true);
  }

  @override
  void dispose() {
    widget.onVisible(false);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: ListTile(
        leading: CircleAvatar(child: Text('${widget.index}')),
        title: Text('Item ${widget.index}'),
        subtitle: Text('构建时间: ${DateTime.now().millisecondsSinceEpoch}'),
      ),
    );
  }
}

六、OpenHarmony 平台适配

在 OpenHarmony 平台上使用列表虚拟化需要注意平台特性适配。

📱 6.1 OpenHarmony 滚动物理效果适配

dart 复制代码
import 'dart:io';

/// OpenHarmony 滚动物理效果适配
class PlatformScrollPhysics {
  static ScrollPhysics getPhysics() {
    if (Platform.isAndroid) {
      return const ClampingScrollPhysics();
    }
    return const BouncingScrollPhysics();
  }
}

/// 平台适配列表示例
class PlatformAdaptedListDemo extends StatelessWidget {
  const PlatformAdaptedListDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('平台适配列表')),
      body: ListView.builder(
        physics: PlatformScrollPhysics.getPhysics(),
        itemCount: 100,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('Item $index'),
            subtitle: Text('平台: ${Platform.operatingSystem}'),
          );
        },
      ),
    );
  }
}

🔄 6.2 OpenHarmony 手势适配

dart 复制代码
/// OpenHarmony 手势适配示例
class OpenHarmonyGestureDemo extends StatefulWidget {
  const OpenHarmonyGestureDemo({super.key});

  @override
  State<OpenHarmonyGestureDemo> createState() => 
      _OpenHarmonyGestureDemoState();
}

class _OpenHarmonyGestureDemoState extends State<OpenHarmonyGestureDemo> {
  final ScrollController _scrollController = ScrollController();
  double _dragDistance = 0;

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('OpenHarmony 手势适配')),
      body: GestureDetector(
        onVerticalDragUpdate: (details) {
          setState(() {
            _dragDistance += details.delta.dy;
          });
        },
        onVerticalDragEnd: (details) {
          if (_dragDistance.abs() > 100) {
            if (_dragDistance > 0) {
              _scrollController.animateTo(
                _scrollController.offset - 200,
                duration: const Duration(milliseconds: 300),
                curve: Curves.easeOut,
              );
            } else {
              _scrollController.animateTo(
                _scrollController.offset + 200,
                duration: const Duration(milliseconds: 300),
                curve: Curves.easeOut,
              );
            }
          }
          setState(() {
            _dragDistance = 0;
          });
        },
        child: ListView.builder(
          controller: _scrollController,
          itemCount: 50,
          itemBuilder: (context, index) {
            return Card(
              margin: const EdgeInsets.all(8),
              child: ListTile(
                leading: CircleAvatar(child: Text('$index')),
                title: Text('列表项 $index'),
                subtitle: Text('拖拽距离: ${_dragDistance.toStringAsFixed(1)}'),
              ),
            );
          },
        ),
      ),
    );
  }
}

七、最佳实践与调试技巧

🎯 7.1 性能优化最佳实践

复制代码
┌─────────────────────────────────────────────────────────────┐
│                  列表虚拟化最佳实践                           │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. 使用 ListView.builder 替代 ListView(children:[])│   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  2. 合理设置 cacheExtent 预加载范围                  │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  3. 使用 addRepaintBoundaries 避免重绘              │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  4. 列表项使用 const 构造函数                        │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  5. 避免在 itemBuilder 中执行耗时操作               │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  6. 使用 AutomaticKeepAliveClientMixin 保持状态     │   │
│  └─────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  7. 分页加载避免一次性加载大量数据                   │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

🔧 7.2 常见问题与解决方案

问题 解决方案
列表滚动卡顿 检查 itemBuilder 是否有耗时操作
内存占用过高 减小 cacheExtent,使用分页加载
列表项状态丢失 使用 AutomaticKeepAliveClientMixin
滚动位置跳动 使用 ScrollController 保持位置
列表项重建频繁 使用 const 构造函数,添加 key
滚动性能差 添加 RepaintBoundary,优化布局层级

📊 7.3 调试技巧

dart 复制代码
/// 列表调试工具
class ListDebugTools {
  static void printScrollInfo(ScrollController controller) {
    print('=== 滚动信息 ===');
    print('当前位置: ${controller.offset}');
    print('最大滚动: ${controller.position.maxScrollExtent}');
    print('最小滚动: ${controller.position.minScrollExtent}');
    print('视口高度: ${controller.position.viewportDimension}');
    print('===============');
  }

  static void printBuildInfo(int index, DateTime startTime) {
    final duration = DateTime.now().difference(startTime);
    print('Item $index 构建耗时: ${duration.inMilliseconds}ms');
  }
}

/// 调试列表示例
class DebugListDemo extends StatefulWidget {
  const DebugListDemo({super.key});

  @override
  State<DebugListDemo> createState() => _DebugListDemoState();
}

class _DebugListDemoState extends State<DebugListDemo> {
  final ScrollController _scrollController = ScrollController();
  int _buildCount = 0;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      ListDebugTools.printScrollInfo(_scrollController);
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('调试列表'),
        actions: [
          IconButton(
            icon: const Icon(Icons.info),
            onPressed: () {
              showDialog(
                context: context,
                builder: (context) => AlertDialog(
                  title: const Text('调试信息'),
                  content: Text('构建次数: $_buildCount'),
                  actions: [
                    TextButton(
                      onPressed: () => Navigator.pop(context),
                      child: const Text('确定'),
                    ),
                  ],
                ),
              );
            },
          ),
        ],
      ),
      body: ListView.builder(
        controller: _scrollController,
        itemCount: 100,
        itemBuilder: (context, index) {
          _buildCount++;
          final startTime = DateTime.now();
        
          return Builder(
            builder: (context) {
              ListDebugTools.printBuildInfo(index, startTime);
              return ListTile(
                title: Text('Item $index'),
                subtitle: Text('构建次数: $_buildCount'),
              );
            },
          );
        },
      ),
    );
  }
}

八、完整示例代码

以下是完整的列表虚拟化系统示例代码:

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:math' as math;
import 'dart:io';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '高性能列表虚拟化系统',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const ListVirtualizationHomePage(),
    );
  }
}

class ListVirtualizationHomePage extends StatelessWidget {
  const ListVirtualizationHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('📊 高性能列表虚拟化系统'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _buildSectionCard(
            context,
            title: 'ListView.builder',
            description: '基础虚拟化列表',
            icon: Icons.list,
            color: Colors.blue,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const BasicListViewDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: '高级 ListView',
            description: '下拉刷新与上拉加载',
            icon: Icons.refresh,
            color: Colors.green,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const AdvancedListViewDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: 'GridView',
            description: '网格虚拟化布局',
            icon: Icons.grid_view,
            color: Colors.orange,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const GridViewDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: 'CustomScrollView',
            description: '组合滚动效果',
            icon: Icons.view_agenda,
            color: Colors.purple,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const CustomScrollViewDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: 'SliverAnimatedList',
            description: '动画列表效果',
            icon: Icons.animation,
            color: Colors.teal,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const SliverAnimatedListDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: '自定义 Sliver',
            description: 'RenderSliver 实现',
            icon: Icons.brush,
            color: Colors.indigo,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const CustomRenderSliverDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: '分页加载',
            description: '大数据量分页处理',
            icon: Icons.pages,
            color: Colors.cyan,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const PaginationDemo()),
            ),
          ),
          _buildSectionCard(
            context,
            title: '性能监控',
            description: '虚拟化性能分析',
            icon: Icons.speed,
            color: Colors.red,
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(builder: (_) => const PerformanceMonitorDemo()),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSectionCard(
    BuildContext context, {
    required String title,
    required String description,
    required IconData icon,
    required Color color,
    required VoidCallback onTap,
  }) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(16),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              Container(
                width: 56,
                height: 56,
                decoration: BoxDecoration(
                  color: color.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Icon(icon, color: color, size: 28),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      description,
                      style: TextStyle(color: Colors.grey[600], fontSize: 14),
                    ),
                  ],
                ),
              ),
              Icon(Icons.chevron_right, color: Colors.grey[400]),
            ],
          ),
        ),
      ),
    );
  }
}

class BasicListViewDemo extends StatelessWidget {
  const BasicListViewDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ListView.builder 基础')),
      body: ListView.builder(
        itemCount: 10000,
        cacheExtent: 500,
        itemBuilder: (context, index) {
          return ListTile(
            leading: CircleAvatar(
              child: Text('${index + 1}'),
            ),
            title: Text('列表项 ${index + 1}'),
            subtitle: Text('这是第 ${index + 1} 个列表项的描述'),
            trailing: const Icon(Icons.chevron_right),
            onTap: () {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('点击了第 ${index + 1} 项')),
              );
            },
          );
        },
      ),
    );
  }
}

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

  @override
  State<AdvancedListViewDemo> createState() => _AdvancedListViewDemoState();
}

class _AdvancedListViewDemoState extends State<AdvancedListViewDemo> {
  final ScrollController _scrollController = ScrollController();
  final List<String> _items = List.generate(100, (index) => 'Item $index');
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.removeListener(_onScroll);
    _scrollController.dispose();
    super.dispose();
  }

  void _onScroll() {
    if (_scrollController.position.pixels >=
        _scrollController.position.maxScrollExtent - 200) {
      _loadMore();
    }
  }

  Future<void> _loadMore() async {
    if (_isLoading) return;
    setState(() => _isLoading = true);
  
    await Future.delayed(const Duration(seconds: 1));
  
    setState(() {
      final startIndex = _items.length;
      for (int i = 0; i < 20; i++) {
        _items.add('Item ${startIndex + i}');
      }
      _isLoading = false;
    });
  }

  Future<void> _onRefresh() async {
    await Future.delayed(const Duration(seconds: 1));
    setState(() {
      _items.clear();
      _items.addAll(List.generate(100, (index) => 'Item $index (刷新)'));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('高级 ListView 配置')),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          controller: _scrollController,
          physics: const BouncingScrollPhysics(),
          cacheExtent: 1000,
          itemCount: _items.length + 1,
          itemBuilder: (context, index) {
            if (index == _items.length) {
              return _buildLoadingIndicator();
            }
            return _buildListItem(index);
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _scrollController.animateTo(
            0,
            duration: const Duration(milliseconds: 500),
            curve: Curves.easeInOut,
          );
        },
        child: const Icon(Icons.arrow_upward),
      ),
    );
  }

  Widget _buildListItem(int index) {
    return Dismissible(
      key: Key(_items[index]),
      background: Container(
        color: Colors.red,
        alignment: Alignment.centerRight,
        padding: const EdgeInsets.only(right: 20),
        child: const Icon(Icons.delete, color: Colors.white),
      ),
      direction: DismissDirection.endToStart,
      onDismissed: (direction) {
        setState(() {
          _items.removeAt(index);
        });
      },
      child: Card(
        margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
        child: ListTile(
          leading: Hero(
            tag: 'item-$index',
            child: CircleAvatar(
              backgroundColor: Colors.primaries[index % Colors.primaries.length],
              child: Text('${index + 1}'),
            ),
          ),
          title: Text(_items[index]),
          subtitle: Text('索引: $index'),
          trailing: const Icon(Icons.chevron_right),
        ),
      ),
    );
  }

  Widget _buildLoadingIndicator() {
    return Container(
      padding: const EdgeInsets.all(16),
      alignment: Alignment.center,
      child: _isLoading
          ? const CircularProgressIndicator()
          : const Text('上拉加载更多'),
    );
  }
}

class GridViewDemo extends StatelessWidget {
  const GridViewDemo({super.key});

  List<Color> get _colors => List.generate(
    100,
    (index) => Color.fromRGBO(
      (index * 25) % 256,
      (index * 50) % 256,
      (index * 75) % 256,
      1.0,
    ),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('GridView 虚拟化')),
      body: GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          mainAxisSpacing: 4,
          crossAxisSpacing: 4,
          childAspectRatio: 1.0,
        ),
        itemCount: 100,
        cacheExtent: 500,
        itemBuilder: (context, index) {
          return GestureDetector(
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => GridDetailPage(
                    index: index,
                    color: _colors[index],
                  ),
                ),
              );
            },
            child: Hero(
              tag: 'grid-item-$index',
              child: Container(
                color: _colors[index],
                child: Center(
                  child: Text(
                    '${index + 1}',
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

class GridDetailPage extends StatelessWidget {
  final int index;
  final Color color;

  const GridDetailPage({
    super.key,
    required this.index,
    required this.color,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: color,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: Text('详情 ${index + 1}'),
      ),
      body: Center(
        child: Hero(
          tag: 'grid-item-$index',
          child: Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              color: color,
              borderRadius: BorderRadius.circular(20),
              boxShadow: [
                BoxShadow(
                  color: Colors.black.withOpacity(0.3),
                  blurRadius: 20,
                  offset: const Offset(0, 10),
                ),
              ],
            ),
            child: Center(
              child: Text(
                '${index + 1}',
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 48,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class CustomScrollViewDemo extends StatelessWidget {
  const CustomScrollViewDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          _buildSliverAppBar(),
          _buildSliverPersistentHeader(),
          _buildSliverGrid(),
          _buildSliverList(),
          _buildSliverFillRemaining(),
        ],
      ),
    );
  }

  Widget _buildSliverAppBar() {
    return SliverAppBar(
      expandedHeight: 200,
      floating: false,
      pinned: true,
      snap: false,
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('CustomScrollView'),
        background: Container(
          decoration: const BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [Colors.blue, Colors.purple],
            ),
          ),
          child: const Center(
            child: Icon(
              Icons.list_alt,
              size: 80,
              color: Colors.white54,
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildSliverPersistentHeader() {
    return SliverPersistentHeader(
      pinned: true,
      delegate: _SectionHeaderDelegate(
        title: '网格区域',
        color: Colors.blue.shade100,
      ),
    );
  }

  Widget _buildSliverGrid() {
    return SliverGrid(
      gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 150,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 1.0,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Container(
            margin: const EdgeInsets.all(4),
            decoration: BoxDecoration(
              color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.3),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Center(
              child: Text(
                'Grid $index',
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          );
        },
        childCount: 12,
      ),
    );
  }

  Widget _buildSliverList() {
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return Card(
            margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
            child: ListTile(
              leading: CircleAvatar(
                child: Text('$index'),
              ),
              title: Text('列表项 $index'),
              subtitle: Text('这是第 $index 个列表项'),
              trailing: const Icon(Icons.chevron_right),
            ),
          );
        },
        childCount: 20,
      ),
    );
  }

  Widget _buildSliverFillRemaining() {
    return SliverFillRemaining(
      hasScrollBody: false,
      child: Container(
        color: Colors.grey.shade200,
        padding: const EdgeInsets.all(32),
        child: const Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.info_outline, size: 48, color: Colors.grey),
            SizedBox(height: 16),
            Text(
              '列表底部区域',
              style: TextStyle(fontSize: 18, color: Colors.grey),
            ),
          ],
        ),
      ),
    );
  }
}

class _SectionHeaderDelegate extends SliverPersistentHeaderDelegate {
  final String title;
  final Color color;

  _SectionHeaderDelegate({required this.title, required this.color});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      color: color,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      child: Align(
        alignment: Alignment.centerLeft,
        child: Text(
          title,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }

  @override
  double get maxExtent => 50;

  @override
  double get minExtent => 50;

  @override
  bool shouldRebuild(covariant _SectionHeaderDelegate oldDelegate) {
    return title != oldDelegate.title || color != oldDelegate.color;
  }
}

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

  @override
  State<SliverAnimatedListDemo> createState() => _SliverAnimatedListDemoState();
}

class _SliverAnimatedListDemoState extends State<SliverAnimatedListDemo> {
  final GlobalKey<SliverAnimatedListState> _listKey = GlobalKey();
  final List<String> _items = List.generate(10, (index) => 'Item $index');
  int _counter = 10;

  void _addItem() {
    final index = _items.length;
    _items.insert(index, 'Item $_counter');
    _listKey.currentState?.insertItem(index);
    _counter++;
  }

  void _removeItem(int index) {
    _listKey.currentState?.removeItem(
      index,
      (context, animation) => _buildRemovedItem(_items[index], animation),
    );
    _items.removeAt(index);
  }

  Widget _buildRemovedItem(String item, Animation<double> animation) {
    return SizeTransition(
      sizeFactor: animation,
      child: Card(
        margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
        color: Colors.red.shade100,
        child: ListTile(
          title: Text(item),
          trailing: const Icon(Icons.delete, color: Colors.red),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SliverAnimatedList')),
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            pinned: true,
            title: const Text('动画列表'),
            actions: [
              IconButton(
                icon: const Icon(Icons.add),
                onPressed: _addItem,
              ),
            ],
          ),
          SliverAnimatedList(
            key: _listKey,
            initialItemCount: _items.length,
            itemBuilder: (context, index, animation) {
              return _buildItem(_items[index], index, animation);
            },
          ),
        ],
      ),
    );
  }

  Widget _buildItem(String item, int index, Animation<double> animation) {
    return SlideTransition(
      position: Tween<Offset>(
        begin: const Offset(1, 0),
        end: Offset.zero,
      ).animate(CurvedAnimation(
        parent: animation,
        curve: Curves.easeOut,
      )),
      child: SizeTransition(
        sizeFactor: animation,
        child: Card(
          margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
          child: ListTile(
            leading: CircleAvatar(
              child: Text('$index'),
            ),
            title: Text(item),
            subtitle: Text('索引: $index'),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () => _removeItem(index),
            ),
          ),
        ),
      ),
    );
  }
}

class CustomRenderSliverDemo extends StatelessWidget {
  const CustomRenderSliverDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('自定义 RenderSliver')),
      body: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Container(
              height: 100,
              color: Colors.blue.shade100,
              child: const Center(child: Text('顶部区域')),
            ),
          ),
          const SpiralSliver(
            itemCount: 30,
            itemSize: 60,
          ),
          SliverToBoxAdapter(
            child: Container(
              height: 100,
              color: Colors.green.shade100,
              child: const Center(child: Text('底部区域')),
            ),
          ),
        ],
      ),
    );
  }
}

class SpiralSliver extends LeafRenderObjectWidget {
  final int itemCount;
  final double itemSize;

  const SpiralSliver({
    super.key,
    required this.itemCount,
    this.itemSize = 50,
  });

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderSpiralSliver(
      itemCount: itemCount,
      itemSize: itemSize,
    );
  }

  @override
  void updateRenderObject(BuildContext context, RenderSpiralSliver renderObject) {
    renderObject
      ..itemCount = itemCount
      ..itemSize = itemSize;
  }
}

class RenderSpiralSliver extends RenderSliver {
  int _itemCount;
  double _itemSize;

  RenderSpiralSliver({
    required int itemCount,
    required double itemSize,
  })  : _itemCount = itemCount,
        _itemSize = itemSize;

  int get itemCount => _itemCount;
  set itemCount(int value) {
    if (_itemCount != value) {
      _itemCount = value;
      markNeedsLayout();
    }
  }

  double get itemSize => _itemSize;
  set itemSize(double value) {
    if (_itemSize != value) {
      _itemSize = value;
      markNeedsLayout();
    }
  }

  @override
  void performLayout() {
    final double totalHeight = _itemCount * _itemSize * 0.5;
  
    geometry = SliverGeometry(
      scrollExtent: totalHeight,
      paintExtent: math.min(totalHeight, constraints.remainingPaintExtent),
      maxPaintExtent: totalHeight,
      hasVisualOverflow: totalHeight > constraints.remainingPaintExtent,
    );
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;
    canvas.save();
    canvas.translate(offset.dx, offset.dy);

    final visibleHeight = geometry!.paintExtent;
  
    for (int i = 0; i < _itemCount; i++) {
      final y = i * _itemSize * 0.5;
    
      if (y + _itemSize < 0 || y > visibleHeight) continue;
    
      final angle = i * 0.3;
      final x = 150 + 50 * math.sin(angle);
    
      final paint = Paint()
        ..color = Colors.primaries[i % Colors.primaries.length]
        ..style = PaintingStyle.fill;
    
      canvas.drawCircle(
        Offset(x, y + _itemSize / 2),
        _itemSize / 3,
        paint,
      );
    }

    canvas.restore();
  }
}

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

  @override
  State<PaginationDemo> createState() => _PaginationDemoState();
}

class _PaginationDemoState extends State<PaginationDemo> {
  final List<DataItem> _items = [];
  final int _pageSize = 20;
  int _currentPage = 0;
  bool _isLoading = false;
  bool _hasMore = true;
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _loadFirstPage();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  Future<void> _loadFirstPage() async {
    await _loadPage();
  }

  void _onScroll() {
    if (_scrollController.position.pixels >=
        _scrollController.position.maxScrollExtent - 200) {
      _loadMore();
    }
  }

  Future<void> _loadPage() async {
    if (_isLoading || !_hasMore) return;

    setState(() => _isLoading = true);

    await Future.delayed(const Duration(milliseconds: 500));

    final newItems = await _fetchItems(_currentPage, _pageSize);
  
    setState(() {
      _items.addAll(newItems);
      _currentPage++;
      _hasMore = newItems.length == _pageSize;
      _isLoading = false;
    });
  }

  Future<void> _loadMore() async {
    await _loadPage();
  }

  Future<List<DataItem>> _fetchItems(int page, int size) async {
    return List.generate(size, (index) {
      final globalIndex = page * size + index;
      return DataItem(
        id: globalIndex,
        title: 'Item $globalIndex',
        subtitle: 'Page ${page + 1}',
      );
    });
  }

  Future<void> _onRefresh() async {
    setState(() {
      _items.clear();
      _currentPage = 0;
      _hasMore = true;
    });
    await _loadPage();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('分页加载')),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          controller: _scrollController,
          itemCount: _items.length + (_hasMore ? 1 : 0),
          itemBuilder: (context, index) {
            if (index == _items.length) {
              return _buildLoadingFooter();
            }
            return _buildItem(_items[index]);
          },
        ),
      ),
    );
  }

  Widget _buildItem(DataItem item) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: ListTile(
        leading: CircleAvatar(child: Text('${item.id}')),
        title: Text(item.title),
        subtitle: Text(item.subtitle),
      ),
    );
  }

  Widget _buildLoadingFooter() {
    return Container(
      padding: const EdgeInsets.all(16),
      alignment: Alignment.center,
      child: _isLoading
          ? const CircularProgressIndicator()
          : const Text('没有更多数据'),
    );
  }
}

class DataItem {
  final int id;
  final String title;
  final String subtitle;

  DataItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
}

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

  @override
  State<PerformanceMonitorDemo> createState() => _PerformanceMonitorDemoState();
}

class _PerformanceMonitorDemoState extends State<PerformanceMonitorDemo> {
  final ScrollController _scrollController = ScrollController();
  int _visibleItemCount = 0;
  int _totalItemCount = 10000;
  double _scrollOffset = 0;
  int _buildCount = 0;
  DateTime? _lastBuildTime;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  void _onScroll() {
    setState(() {
      _scrollOffset = _scrollController.offset;
    });
  }

  void _onBuild() {
    final now = DateTime.now();
    if (_lastBuildTime != null) {
      final diff = now.difference(_lastBuildTime!).inMilliseconds;
      if (diff < 16) {
        _buildCount++;
      }
    }
    _lastBuildTime = now;
  }

  void _updateVisibleCount(bool visible) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        setState(() {
          if (visible) {
            _visibleItemCount++;
          } else {
            _visibleItemCount = _visibleItemCount > 0 
                ? _visibleItemCount - 1 
                : 0;
          }
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('性能监控')),
      body: Column(
        children: [
          _buildPerformancePanel(),
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              itemCount: _totalItemCount,
              cacheExtent: 500,
              itemBuilder: (context, index) {
                _onBuild();
                return _PerformanceMonitoredItem(
                  index: index,
                  onVisible: _updateVisibleCount,
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPerformancePanel() {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.blue.shade50,
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            blurRadius: 4,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildMetric('总项数', '$_totalItemCount'),
              _buildMetric('可见项', '$_visibleItemCount'),
              _buildMetric('滚动位置', '${_scrollOffset.toStringAsFixed(0)}px'),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildMetric('构建次数', '$_buildCount'),
              _buildMetric('帧率', _buildCount < 60 ? '60fps' : '低'),
              _buildMetric('内存', '虚拟化'),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildMetric(String label, String value) {
    return Column(
      children: [
        Text(
          value,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Colors.blue,
          ),
        ),
        Text(
          label,
          style: TextStyle(
            fontSize: 12,
            color: Colors.grey[600],
          ),
        ),
      ],
    );
  }
}

class _PerformanceMonitoredItem extends StatefulWidget {
  final int index;
  final Function(bool) onVisible;

  const _PerformanceMonitoredItem({
    required this.index,
    required this.onVisible,
  });

  @override
  State<_PerformanceMonitoredItem> createState() => 
      _PerformanceMonitoredItemState();
}

class _PerformanceMonitoredItemState 
    extends State<_PerformanceMonitoredItem> {
  @override
  void initState() {
    super.initState();
    widget.onVisible(true);
  }

  @override
  void dispose() {
    widget.onVisible(false);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: ListTile(
        leading: CircleAvatar(child: Text('${widget.index}')),
        title: Text('Item ${widget.index}'),
        subtitle: Text('构建时间: ${DateTime.now().millisecondsSinceEpoch}'),
      ),
    );
  }
}

九、总结

本文深入探讨了 Flutter for OpenHarmony 的高性能列表虚拟化系统,从架构原理到具体实现,涵盖了以下核心内容:

📚 核心知识点回顾

  1. 虚拟化架构:理解 Viewport、Sliver、Scrollable 三层架构的工作原理
  2. 基础实现:掌握 ListView.builder、GridView 的虚拟化配置
  3. Sliver 家族:灵活运用 CustomScrollView 组合各种滚动效果
  4. 自定义 Sliver:通过 RenderSliver 实现独特的滚动布局
  5. 优化策略:列表项缓存、分页加载、性能监控
  6. 平台适配:OpenHarmony 平台的滚动物理效果和手势适配

🎯 最佳实践要点

  • 始终使用 builder 构造函数处理大数据量
  • 合理配置 cacheExtent 平衡性能与体验
  • 使用 AutomaticKeepAliveClientMixin 保持状态
  • 分页加载避免内存压力
  • 添加 RepaintBoundary 优化重绘

🚀 进阶方向

  • 深入研究 RenderSliver 的布局协议
  • 实现更复杂的自定义滚动效果
  • 探索列表项的预加载策略
  • 结合 Isolate 处理大数据计算

通过掌握这些技术,你可以构建出高性能、流畅的大数据量列表应用,为用户提供优质的滚动体验。


💡 提示:在实际项目中,建议使用 Flutter DevTools 进行性能分析,及时发现和解决列表性能问题。

相关推荐
2501_921930832 小时前
进阶实战 Flutter for OpenHarmony:自定义渲染引擎系统 - RenderObject 底层绘制实现
flutter
早點睡3902 小时前
Harmony Flutter 跨平台开发实战:鸿蒙与音乐律动艺术、粒子物理引力场:万有引力与排斥逻辑
flutter·华为·harmonyos
九狼3 小时前
Riverpod 2.0 代码生成与依赖注入
flutter·设计模式·github
空白诗3 小时前
Harmony Flutter 跨平台开发实战:鸿蒙与音乐律动艺术、傅里叶变换与频谱:从时域到频域的视觉翻译
flutter
2601_949593653 小时前
Harmony Flutter 跨平台开发实战:鸿蒙与音乐律动艺术、极坐标对称投影:万花筒般的几何韵律
flutter·华为·harmonyos
阿林来了3 小时前
Flutter三方库适配OpenHarmony【flutter_web_auth】— Dart 层源码逐行解析
flutter
心之语歌3 小时前
Flutter Provider 使用教程:Consumer/of/watch/read 全解析
flutter
2601_949593653 小时前
Harmony Flutter 跨平台开发实战:鸿蒙与音乐律动艺术、Voronoi 泰森多边形:空间分割的动态演化
flutter·华为·harmonyos
松叶似针3 小时前
Flutter三方库适配OpenHarmony【doc_text】— Word 文档解析插件功能全景与适配价值
flutter·word·harmonyos