Flutter Instagram风格故事板插件flutter_instagram_storyboard的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter Instagram风格故事板插件 flutter_instagram_storyboard 的使用

简介

flutter_instagram_storyboard 是一个用于创建类似于 Instagram 故事板的 Flutter 插件。尽管目前它仍处于早期发布阶段,缺少一些有用的功能,但已经可以使用,并且只需进行一些小调整即可。

主要功能

  • 一个可以自动标记为“已观看”的故事按钮列表
  • 类似于 Instagram 的 3D 页面视图列表
  • 自定义导航
  • 默认的故事板结构

尚未实现的功能

  • 允许从后端请求故事的按钮预加载器
  • 在后台预加载可见故事的懒加载器

示例 GIF

开始使用

最简单的开始方式是使用内置的 StoryListView 来创建故事按钮。它接受一个 StoryButtonData 对象列表,这些对象包含每个故事的所有设置,包括页面列表、每个页面的时间以及许多其他设置。页面可以完全自定义,它们只是小部件。

使用方法

以下是一个完整的示例代码:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: const StoryExamplePage(),
    );
  }
}

class StoryExamplePage extends StatefulWidget {
  const StoryExamplePage({Key? key}) : super(key: key);

  @override
  State<StoryExamplePage> createState() => _StoryExamplePageState();
}

class _StoryExamplePageState extends State<StoryExamplePage> {
  static const double _borderRadius = 100.0;
  final StoryTimelineController storyController = StoryTimelineController();

  Widget _createDummyPage({
    required String text,
    required String imageName,
    bool addBottomBar = true,
  }) {
    return StoryPageScaffold(
      bottomNavigationBar: addBottomBar
          ? SizedBox(
              width: double.infinity,
              height: kBottomNavigationBarHeight,
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 20.0),
                child: Row(
                  children: [
                    Expanded(
                      child: Container(
                        width: double.infinity,
                        height: double.infinity,
                        decoration: BoxDecoration(
                          border: Border.all(color: Colors.white, width: 2.0),
                          borderRadius: BorderRadius.circular(_borderRadius),
                        ),
                      ),
                    ),
                    const Padding(
                      padding: EdgeInsets.all(8.0),
                      child: Icon(Icons.send, color: Colors.white),
                    ),
                  ],
                ),
              ),
            )
          : const SizedBox.shrink(),
      body: Container(
        width: double.infinity,
        height: double.infinity,
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/$imageName.png'),
            fit: BoxFit.cover,
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              Text(
                text,
                style: const TextStyle(color: Colors.white, fontSize: 30.0, fontWeight: FontWeight.bold),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildButtonChild(String text) {
    return Padding(
      padding: const EdgeInsets.all(5.0),
      child: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          const SizedBox(height: 100.0),
          Text(
            text,
            style: const TextStyle(color: Colors.black, fontWeight: FontWeight.normal, fontSize: 11.0),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  BoxDecoration _buildButtonDecoration(String imageName) {
    return BoxDecoration(
      borderRadius: BorderRadius.circular(_borderRadius),
      image: DecorationImage(
        image: AssetImage('assets/images/$imageName.png'),
        fit: BoxFit.cover,
      ),
    );
  }

  BoxDecoration _buildBorderDecoration(Color color) {
    return BoxDecoration(
      borderRadius: const BorderRadius.all(Radius.circular(_borderRadius)),
      border: Border.fromBorderSide(BorderSide(color: color, width: 1.5)),
    );
  }

  @override
  void initState() {
    super.initState();
    storyController.addListener(_onStoryEvent);
  }

  void _onStoryEvent(event, storyId) {
    print('event=> $event  storyId $storyId');
  }

  @override
  void dispose() {
    storyController.removeListener(_onStoryEvent);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        title: const Text('Story Example'),
      ),
      body: Column(
        children: [
          StoryListView(
            listHeight: 180.0,
            pageTransform: const StoryPage3DTransform(),
            buttonDatas: [
              StoryButtonData(
                storyId: "1",
                showAddButton: true,
                storyController: storyController,
                timelineBackgroundColor: Colors.red,
                buttonDecoration: _buildButtonDecoration('car'),
                child: _buildButtonChild('Want a new car?'),
                onAddStoryPressed: () {
                  print('onAddStoryPressed');
                },
                borderDecoration: _buildBorderDecoration(Colors.red),
                storyPages: [
                  _createDummyPage(
                    text: 'Want to buy a new car? Get our loan for the rest of your life!',
                    imageName: 'car',
                  ),
                  _createDummyPage(
                    text: 'Can\'t return the loan? Don\'t worry, we\'ll take your soul as a collateral ;-)',
                    imageName: 'car',
                  ),
                ],
                segmentDuration: [const Duration(seconds: 15), const Duration(seconds: 3)],
              ),
              StoryButtonData(
                storyId: "2",
                storyController: storyController,
                timelineBackgroundColor: Colors.blue,
                buttonDecoration: _buildButtonDecoration('travel_1'),
                borderDecoration: _buildBorderDecoration(const Color.fromARGB(255, 134, 119, 95)),
                child: _buildButtonChild('Travel whereever'),
                storyPages: [
                  _createDummyPage(text: 'Get a loan', imageName: 'travel_1', addBottomBar: false),
                  _createDummyPage(text: 'Select a place where you want to go', imageName: 'travel_2', addBottomBar: false),
                  _createDummyPage(text: 'Dream about the place and pay our interest', imageName: 'travel_3', addBottomBar: false),
                ],
                segmentDuration: [
                  const Duration(seconds: 3),
                  const Duration(seconds: 3),
                  const Duration(seconds: 3),
                ],
              ),
              // Add more StoryButtonData here...
            ],
          ),
        ],
      ),
    );
  }
}

额外信息

该插件仍在开发中,主要用于我正在参与的一些项目中。如果你有兴趣参与开发,请随时提交拉取请求,但请确保你的代码符合主要的 Dart 语言指南。


更多关于Flutter Instagram风格故事板插件flutter_instagram_storyboard的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Instagram风格故事板插件flutter_instagram_storyboard的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 flutter_instagram_storyboard 插件来创建一个 Instagram 风格故事板的示例代码。这个插件允许你在 Flutter 应用中实现类似 Instagram 的故事板界面,包括滑动切换故事、添加导航栏等功能。

首先,你需要在你的 pubspec.yaml 文件中添加 flutter_instagram_storyboard 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_instagram_storyboard: ^最新版本号  # 请替换为实际的最新版本号

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

接下来,在你的 Dart 文件中编写代码。以下是一个简单的示例,展示如何使用 flutter_instagram_storyboard 插件:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: StoryBoardScreen(),
    );
  }
}

class StoryBoardScreen extends StatefulWidget {
  @override
  _StoryBoardScreenState createState() => _StoryBoardScreenState();
}

class _StoryBoardScreenState extends State<StoryBoardScreen> {
  List<String> stories = [
    'https://example.com/story1.jpg',  // 替换为你的图片URL
    'https://example.com/story2.jpg',  // 替换为你的图片URL
    'https://example.com/story3.jpg',  // 替换为你的图片URL
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: InstagramStoryBoard(
        stories: stories,
        indicatorColor: Colors.white,
        indicatorActiveColor: Colors.black,
        onStoryClick: (index) {
          // 点击故事时的回调
          print('Story clicked at index: $index');
        },
        onPageChanged: (index) {
          // 页面切换时的回调
          print('Page changed to index: $index');
        },
        navigationBar: NavigationBar(
          leading: IconButton(
            icon: Icon(Icons.arrow_back_ios),
            onPressed: () {
              Navigator.pop(context);
            },
          ),
          trailing: IconButton(
            icon: Icon(Icons.more_vert),
            onPressed: () {
              // 显示更多选项的菜单
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('More options')),
              );
            },
          ),
          title: Text('Stories'),
          center: Icon(Icons.add),
          onCenterIconPressed: () {
            // 添加新故事的按钮点击事件
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Add New Story')),
            );
          },
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们定义了一个 MyApp 类作为应用的入口。
  2. StoryBoardScreen 是我们的主屏幕,它包含了一个状态类 _StoryBoardScreenState
  3. _StoryBoardScreenState 中,我们定义了一个 stories 列表,包含了故事图片的 URL。
  4. 我们使用 InstagramStoryBoard 组件来展示故事板,并传递了故事列表、指示器颜色、点击和页面切换的回调。
  5. NavigationBar 组件用于显示导航栏,包括返回按钮、更多选项按钮和添加新故事的按钮。

你可以根据需要进一步自定义这个示例,比如调整布局、添加更多功能等。希望这个示例能帮助你快速上手 flutter_instagram_storyboard 插件的使用。

回到顶部