Flutter折叠列表动画插件paperfold_list的使用

Flutter折叠列表动画插件paperfold_list的使用

<paperfold_list> pub.dev GitHub Actions MIT License </paperfold_list>

灵感来源于 PaperfoldJs

Paperfold List 是一个 Flutter 小部件,它创建了一个可以像纸一样展开和折叠的可扩展列表视图。这个小部件允许用户获得一种视觉上吸引人且交互式的列表体验,支持自定义动画和效果。

预览

特性

  • 支持带有折叠纸效果的可扩展列表视图。
  • 支持水平和垂直两种列表方向。
  • 平滑且可自定义的展开和折叠动画。

示例用法

主要小部件

Paperfold List 可以这样创建:

PaperfoldList(
  itemExtent: 100,
  targetUnfold: 0.5,
  axis: PaperfoldAxis.vertical,
  axisSize: PaperfoldAxisSize.min,
  axisAlignment: PaperfoldAxisAlignment.start,
  animationDuration: const Duration(milliseconds: 500),
  animationCurve: Curves.ease,
  perspective: 0.0015,
  firstChildFoldsInward: true,
  unmountOnFold: true,
  interactionUnfoldThreshold: 1.0,
  effect: PaperfoldShadeEffect(),
  children: const [
    Text("First"),
    Text("Second"),
    Text("Third"),
  ],
)

使用构建器模式创建列表:

PaperfoldList.builder(
  itemExtent: 100,
  targetUnfold: 0.5,
  itemCount: 3,
  itemBuilder: (context, index) => Text("Child $index"),
)

有关参数的详细信息,请参阅 PaperfoldList 文档

效果

PaperfoldEffect 类提供了一种通过包装每个子项来添加额外效果的方法,这些效果基于列表折叠的程度和其他属性绘制在子项上。

提供的三种效果类型:

  • PaperfoldNoEffect:不装饰子项。

示例:

PaperfoldList(
  effect: PaperfoldNoEffect(),
)
  • PaperfoldShadeEffect:默认效果(未指定时)。这是一个预设效果,包含各种选项以快速包含一些阴影效果。

示例:

PaperfoldList(
  effect: PaperfoldShadeEffect(
    backgroundColor: Colors.white,
    inwardOverlay: Colors.black54,
    inwardCrease: Colors.black12,
  ),
)

有关参数的详细信息,请参阅 PaperfoldShadeEffect 文档

  • PaperfoldListCustomEffect:使用 PaperfoldEffectBuilder 定义自定义效果。

示例效果:当列表折叠时,渐隐子项。

PaperfoldList(
  effect: PaperfoldListCustomEffect(
    builder: (context, info, child) {
      return Opacity(
        opacity: info.unfold,
        child: child,
      );
    }
  ),
)

问题

遇到问题?请在 GitHub 上提出。

示例代码

以下是一个完整的示例代码,展示了如何使用 PaperfoldList 创建一个带有折叠动画的列表:

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

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

class Post {
  final int id;
  final String userImageUrl;
  final String userName;
  final String content;

  const Post({
    required this.id,
    required this.userImageUrl,
    required this.userName,
    required this.content,
  });
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.light(useMaterial3: true),
      home: const ExamplePage(),
    );
  }
}

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

  [@override](/user/override)
  State<ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  static const List<Post> _posts = [
    Post(
      id: 1,
      userImageUrl: 'https://randomuser.me/api/portraits/men/1.jpg',
      userName: 'John Miller',
      content: 'Just had a great day at the beach!',
    ),
    Post(
      id: 2,
      userImageUrl: 'https://randomuser.me/api/portraits/women/2.jpg',
      userName: 'Jane Smith',
      content: 'Loving the new coffee place downtown.',
    ),
    Post(
      id: 3,
      userImageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
      userName: 'Michael Johnson',
      content: 'Started a new book today. Excited to dive in!',
    ),
    Post(
      id: 4,
      userImageUrl: 'https://randomuser.me/api/portraits/women/4.jpg',
      userName: 'Emily Davis',
      content: 'Had an amazing dinner with friends.',
    ),
    Post(
      id: 5,
      userImageUrl: 'https://randomuser.me/api/portraits/men/5.jpg',
      userName: 'Chris Brown',
      content: 'Just finished a 5k run. Feeling great!',
    ),
    Post(
      id: 6,
      userImageUrl: 'https://randomuser.me/api/portraits/women/6.jpg',
      userName: 'Sarah Wilson',
      content: 'Baking some cookies today. Can’t wait to taste them!',
    ),
    Post(
      id: 7,
      userImageUrl: 'https://randomuser.me/api/portraits/men/7.jpg',
      userName: 'David Lee',
      content: 'Enjoying a beautiful sunset at the park.',
    ),
    Post(
      id: 8,
      userImageUrl: 'https://randomuser.me/api/portraits/women/8.jpg',
      userName: 'Olivia Martinez',
      content: 'Just finished reading an amazing book!',
    ),
  ];

  final double _itemExtent = 80;

  bool _folded = true;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Recent Posts"),
        actions: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.add),
          ),
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            _buildPost(_posts.first),
            PaperfoldList.builder(
              targetUnfold: _folded ? 0 : 1,
              axis: PaperfoldAxis.vertical,
              itemExtent: _itemExtent,
              itemCount: _posts.length - 2,
              interactionUnfoldThreshold: 1,
              unmountOnFold: true,
              animationCurve: Curves.easeInOut,
              animationDuration: const Duration(milliseconds: 500),
              effect: PaperfoldShadeEffect(
                backgroundColor: Theme.of(context).scaffoldBackgroundColor,
                preBuilder: (context, info, child) => Material(child: child),
              ),
              itemBuilder: (context, index) {
                final post = _posts[index + 1];
                return _buildPost(post);
              },
            ),
            _buildPost(_posts.last),
            const SizedBox(height: 8),
            _buildShowMoreLessButton(),
          ],
        ),
      ),
    );
  }

  Widget _buildPost(Post post) {
    return SizedBox(
      height: _itemExtent,
      child: ListTile(
        onTap: () {},
        leading: CircleAvatar(
          foregroundImage: NetworkImage(post.userImageUrl),
        ),
        title: Text(post.userName),
        subtitle: Text(
          post.content,
          maxLines: 2,
          overflow: TextOverflow.ellipsis,
        ),
      ),
    );
  }

  Widget _buildShowMoreLessButton() {
    return TextButton(
      onPressed: () {
        setState(() {
          _folded = !_folded;
        });
      },
      child: Text(_folded ? "Show More" : "Show Less"),
    );
  }
}

更多关于Flutter折叠列表动画插件paperfold_list的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter折叠列表动画插件paperfold_list的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用paperfold_list插件来实现折叠列表动画的示例代码。paperfold_list是一个用于创建折叠列表动画效果的Flutter插件。

首先,确保你已经在pubspec.yaml文件中添加了paperfold_list依赖:

dependencies:
  flutter:
    sdk: flutter
  paperfold_list: ^0.0.4  # 请检查最新版本号

然后运行flutter pub get来获取依赖。

接下来是一个完整的示例代码,展示如何使用paperfold_list插件:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PaperFold List Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 300),
      vsync: this,
    )..repeat(reverse: true);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('PaperFold List Example'),
      ),
      body: PaperFoldList(
        initialFoldIndex: 0,
        children: List.generate(
          10,
          (index) => PaperFoldTile(
            title: Text('Item $index'),
            content: Container(
              height: 100,
              color: Colors.grey[200],
              child: Center(child: Text('Content of Item $index')),
            ),
            onTap: () {
              print('Item $index tapped');
            },
          ),
        ),
        animationController: _controller,
      ),
    );
  }
}

代码解释

  1. 依赖引入:在pubspec.yaml中添加paperfold_list依赖。
  2. MaterialApp:创建了一个基本的Flutter应用。
  3. StatefulWidgetMyHomePage是一个有状态的组件,用于管理动画控制器。
  4. AnimationController:用于控制折叠动画。在initState中初始化,并在dispose中释放资源。
  5. PaperFoldListPaperFoldList组件接受一个initialFoldIndex参数来指定初始折叠的索引,以及一个children列表,每个子项是一个PaperFoldTile
  6. PaperFoldTile:每个PaperFoldTile包含标题(title)、内容(content)和一个点击回调(onTap)。

这个示例展示了如何创建一个包含10个项目的折叠列表,每个项目在点击时会打印出相应的索引。动画控制器会不断重复动画,但你可以根据需求调整动画行为。

请根据你的具体需求调整代码,例如添加更多内容、自定义动画效果等。

回到顶部