Flutter动态GIF展示对话框插件giffy_dialog的使用

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

Flutter动态GIF展示对话框插件giffy_dialog的使用

Giffy Dialog

Open Source Love License Dart CI CodeCov Version

Giffy Dialog 是一个受 FancyAlertDialog-Android 启发的Flutter库,用于创建带有动态GIF的自定义对话框。

显示一些❤️并为项目加星以支持它

在线演示: https://xsahil03x.github.io/giffy_dialog

An animated image of the GiffyDialog

从v1迁移到v2

请参考migration guide来了解如何从v1迁移到v2。

安装

在你的 pubspec.yaml 文件中添加以下内容,并将 [version] 替换为最新版本:

dependencies:
  giffy_dialog: ^[version]

使用方法

导入包

import 'package:giffy_dialog/giffy_dialog.dart';

显示对话框

showDialog(
  context: context,
  builder: (BuildContext context) {
    return GiffyDialog.image(
      Image.network(
        "https://raw.githubusercontent.com/Shashank02051997/FancyGifDialog-Android/master/GIF's/gif14.gif",
        height: 200,
        fit: BoxFit.cover,
      ),
      title: Text(
        'Image Animation',
        textAlign: TextAlign.center,
      ),
      content: Text(
        'This is a image animation dialog box. This library helps you easily create fancy giffy dialog.',
        textAlign: TextAlign.center,
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, 'CANCEL'),
          child: const Text('CANCEL'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, 'OK'),
          child: const Text('OK'),
        ),
      ],
    );
  },
);

显示底部弹出窗口

showModalBottomSheet(
  context: context,
  clipBehavior: Clip.antiAlias,
  isScrollControlled: true,
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(
      top: Radius.circular(useMaterial3 ? 32 : 4),
    ),
  ),
  builder: (BuildContext context) {
    return GiffyBottomSheet.image(
      Image.network(
        "https://raw.githubusercontent.com/Shashank02051997/FancyGifDialog-Android/master/GIF's/gif14.gif",
        height: 200,
        fit: BoxFit.cover,
      ),
      title: Text(
        'Image Animation',
        textAlign: TextAlign.center,
      ),
      content: Text(
        'This is a image animation bottom sheet. This library helps you easily create fancy giffy bottom sheet.',
        textAlign: TextAlign.center,
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, 'CANCEL'),
          child: const Text('CANCEL'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, 'OK'),
          child: const Text('OK'),
        ),
      ],
    );
  },
);

示例代码

以下是一个完整的示例代码,展示了如何使用 Giffy DialogGiffy BottomSheet 来创建不同类型的动画对话框和底部弹出窗口。

import 'package:flutter/material.dart';
import 'package:giffy_dialog/giffy_dialog.dart';
import 'package:google_fonts/google_fonts.dart';

void main() => runApp(MyApp());

final material3Notifier = ValueNotifier<bool>(true);

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<bool>(
      valueListenable: material3Notifier,
      builder: (context, useMaterial3, _) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Giffy Demo',
          theme: ThemeData(
            brightness: Brightness.light,
            useMaterial3: useMaterial3,
            colorSchemeSeed: Colors.teal,
            textTheme: GoogleFonts.ralewayTextTheme(),
          ),
          darkTheme: ThemeData(
            brightness: Brightness.dark,
            useMaterial3: useMaterial3,
            colorSchemeSeed: Colors.teal,
            textTheme: GoogleFonts.ralewayTextTheme(),
          ),
          home: MyHomePage(),
        );
      },
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Giffy Example"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            MaterialToggleButtons(),
            SizedBox(height: 30),
            Text('Image Giffy'),
            SizedBox(height: 10),
            TypedExample(type: GiffyType.image),
            SizedBox(height: 30),
            Text('Rive Giffy'),
            SizedBox(height: 10),
            TypedExample(type: GiffyType.rive),
            SizedBox(height: 30),
            Text('Lottie Giffy'),
            SizedBox(height: 10),
            TypedExample(type: GiffyType.lottie),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final useMaterial3 = Theme.of(context).useMaterial3;
    final primary = Theme.of(context).colorScheme.primary;
    final isDark = Theme.of(context).brightness == Brightness.dark;

    final selectedColor = useMaterial3
        ? primary
        : isDark
            ? Colors.black
            : Colors.white;
    final borderColor = useMaterial3 ? primary.withOpacity(0.12) : primary;
    final borderRadius = useMaterial3
        ? const BorderRadius.all(Radius.circular(16))
        : const BorderRadius.all(Radius.circular(4));

    return ToggleButtons(
      isSelected: [!useMaterial3, useMaterial3],
      borderRadius: borderRadius,
      borderColor: borderColor,
      selectedBorderColor: borderColor,
      color: primary,
      selectedColor: selectedColor,
      fillColor: borderColor,
      constraints: const BoxConstraints(
        minHeight: 30.0,
        minWidth: 100.0,
      ),
      onPressed: (index) {
        material3Notifier.value = index == 1;
      },
      children: [Text('Material 2'), Text('Material 3')],
    );
  }
}

enum GiffyType {
  image,
  rive,
  lottie;

  Widget when({
    required Widget Function() image,
    required Widget Function() rive,
    required Widget Function() lottie,
  }) {
    switch (this) {
      case GiffyType.image:
        return image();
      case GiffyType.rive:
        return rive();
      case GiffyType.lottie:
        return lottie();
    }
  }
}

class TypedExample extends StatelessWidget {
  const TypedExample({
    super.key,
    required this.type,
  });

  final GiffyType type;

  @override
  Widget build(BuildContext context) {
    final useMaterial3 = Theme.of(context).useMaterial3;

    final image = GiffyModel.image(context);
    final rive = GiffyModel.rive(context);
    final lottie = GiffyModel.lottie(context);

    Widget buildDialog() {
      return type.when(
        image: () {
          return GiffyDialog.image(
            image.giffy as Image,
            title: image.title,
            content: image.content,
            actions: image.actions,
          );
        },
        rive: () {
          return GiffyDialog.rive(
            rive.giffy as RiveAnimation,
            giffyBuilder: (context, rive) {
              return ClipRRect(
                borderRadius: useMaterial3
                    ? const BorderRadius.all(Radius.circular(16))
                    : const BorderRadius.all(Radius.circular(4)),
                child: SizedBox(height: 200, child: rive),
              );
            },
            title: rive.title,
            content: rive.content,
            actions: rive.actions,
          );
        },
        lottie: () {
          return GiffyDialog.lottie(
            lottie.giffy as LottieBuilder,
            title: lottie.title,
            content: lottie.content,
            actions: lottie.actions,
          );
        },
      );
    }

    Widget buildBottomSheet() {
      return type.when(
        image: () {
          return GiffyBottomSheet.image(
            image.giffy as Image,
            title: image.title,
            content: image.content,
            actions: image.actions,
          );
        },
        rive: () {
          return GiffyBottomSheet.rive(
            rive.giffy as RiveAnimation,
            giffyBuilder: (context, rive) {
              return ClipRRect(
                borderRadius: useMaterial3
                    ? const BorderRadius.all(Radius.circular(16))
                    : const BorderRadius.all(Radius.circular(4)),
                child: SizedBox(height: 200, child: rive),
              );
            },
            title: rive.title,
            content: rive.content,
            actions: rive.actions,
          );
        },
        lottie: () {
          return GiffyBottomSheet.lottie(
            lottie.giffy as LottieBuilder,
            title: lottie.title,
            content: lottie.content,
            actions: lottie.actions,
          );
        },
      );
    }

    return SizedBox(
      height: 36,
      child: Row(
        children: [
          Expanded(
            child: ElevatedButton(
              child: Text('Show Dialog'),
              onPressed: () {
                showDialog(
                  context: context,
                  builder: (_) {
                    return buildDialog();
                  },
                );
              },
            ),
          ),
          VerticalDivider(),
          Expanded(
            child: ElevatedButton(
              child: Text('Show Bottom Sheet'),
              onPressed: () {
                showModalBottomSheet(
                  context: context,
                  clipBehavior: Clip.antiAlias,
                  isScrollControlled: true,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.vertical(
                      top: Radius.circular(useMaterial3 ? 32 : 4),
                    ),
                  ),
                  builder: (_) {
                    return buildBottomSheet();
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

class GiffyModel {
  final Widget giffy;
  final Widget title;
  final Widget content;
  final List<Widget> actions;

  const GiffyModel({
    required this.giffy,
    required this.title,
    required this.content,
    required this.actions,
  });

  factory GiffyModel.image(BuildContext context) {
    return GiffyModel(
      giffy: Image.network(
        "https://raw.githubusercontent.com/Shashank02051997/FancyGifDialog-Android/master/GIF's/gif14.gif",
        height: 200,
        fit: BoxFit.cover,
      ),
      title: Text(
        'Image Animation',
        textAlign: TextAlign.center,
      ),
      content: Text(
        'This is a image animation dialog box. This library helps you easily create fancy giffy dialog.',
        textAlign: TextAlign.center,
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, 'CANCEL'),
          child: const Text('CANCEL'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, 'OK'),
          child: const Text('OK'),
        ),
      ],
    );
  }

  factory GiffyModel.rive(BuildContext context) {
    return GiffyModel(
      giffy: RiveAnimation.network(
        'https://cdn.rive.app/animations/vehicles.riv',
        fit: BoxFit.cover,
        placeHolder: Center(child: CircularProgressIndicator()),
      ),
      title: Text(
        'Rive Animation',
        textAlign: TextAlign.center,
      ),
      content: Text(
        'This is a rive animation dialog box. This library helps you easily create fancy giffy dialog.',
        textAlign: TextAlign.center,
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, 'CANCEL'),
          child: const Text('CANCEL'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, 'OK'),
          child: const Text('OK'),
        ),
      ],
    );
  }

  factory GiffyModel.lottie(BuildContext context) {
    return GiffyModel(
      giffy: Lottie.network(
        'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json',
        fit: BoxFit.contain,
        height: 200,
      ),
      title: Text(
        'Lottie Animation',
        textAlign: TextAlign.center,
      ),
      content: Text(
        'This is a lottie animation dialog box. This library helps you easily create fancy giffy dialog.',
        textAlign: TextAlign.center,
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, 'CANCEL'),
          child: const Text('CANCEL'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, 'OK'),
          child: const Text('OK'),
        ),
      ],
    );
  }
}

自定义选项

GiffyDialog 提供了多种自定义选项,例如对话框标题、描述、按钮、动画等。请参考 官方文档 获取更多信息。

贡献者

感谢所有贡献者,他们为这个项目做出了巨大贡献。

许可证

本项目遵循 MIT License


希望这个帖子能帮助你更好地理解和使用 giffy_dialog 插件。如果你有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter动态GIF展示对话框插件giffy_dialog的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动态GIF展示对话框插件giffy_dialog的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用giffy_dialog插件来展示动态GIF的示例代码。这个插件允许你轻松地在一个对话框中展示GIF图像。

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

dependencies:
  flutter:
    sdk: flutter
  giffy_dialog: ^2.0.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来,你可以在你的Flutter应用中使用GiffyDialog来展示GIF。以下是一个完整的示例代码:

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

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

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

class MyHomePage extends StatelessWidget {
  final String gifUrl = 'https://example.com/path/to/your/gif.gif'; // 替换为你的GIF URL

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GiffyDialog Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => showGiffyDialog(context, gifUrl),
          child: Text('Show GIF'),
        ),
      ),
    );
  }

  void showGiffyDialog(BuildContext context, String gifUrl) {
    GiffyDialog.builder(
      context: context,
      initialTitle: 'GIF Dialog',
      image: NetworkImage(gifUrl),
      description: 'This is a demo GIF',
      onOkButtonClicked: () {
        // 点击确定按钮后的回调
        print('OK button clicked');
      },
      onCancelButtonClicked: () {
        // 点击取消按钮后的回调
        print('Cancel button clicked');
      },
      shouldDisposeWhenClose: true,
      // 其他可选参数,如标题、描述、按钮文本等,可以根据需要配置
    ).show();
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮。点击按钮时,会调用showGiffyDialog函数,该函数使用GiffyDialog.builder来显示一个包含GIF的对话框。

请注意以下几点:

  1. gifUrl应该替换为你实际想要展示的GIF图像的URL。
  2. GiffyDialog.builder提供了许多可选参数,如initialTitledescriptiononOkButtonClickedonCancelButtonClicked等,你可以根据需要进行配置。
  3. shouldDisposeWhenClose参数决定对话框关闭后是否释放资源。

这个示例展示了如何使用giffy_dialog插件在Flutter应用中展示动态GIF图像。希望这对你有所帮助!

回到顶部