Flutter图像合成插件montage的使用

Flutter图像合成插件montage的使用

montage

组织你的动画。

快速开始

// 1. 定义你的动画
const entrance = MontageAnimation(
  key: 'entrance',
  duration: Duration(seconds: 2), 
);

const exit = MontageAnimation(
  key: 'exit',
  duration: Duration(seconds: 2),
);

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

  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> with TickerProviderStateMixin {
  MontageController? controller;

  @override
  void initState() {
    controller = MontageController(
      vsync: this,
      initialAnimation: entrance,
    );
    super.initState();
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: ValueListenableBuilder<MontageAnimation?>(
          valueListenable: controller!.current,
          builder: (context, current, child) => Text(current?.key ?? 'none'),
        ),
      ),
      // 2. 将你的动画组件包裹在带有控制器的Montage中。
      body: Montage( 
        controller: controller!,
        child: BasicScene(),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          /// 播放这些动画序列
          controller!.play([
            entrance,
            exit,
          ]);
        },
        label: Text('播放'),
        icon: Icon(Icons.video_call),
      ),
    );
  }
}

class BasicScene extends StatelessWidget {
  const BasicScene({
    Key? key,
  }) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        // 3. 使用定义了每个动画运动的motion组件
        Motion(
          motion: {
            // 你可以使用提供的motion或自定义的motion
            entrance: Motions.combine([
              Motions.rotate(startTurns: -1, endTurns: 0),
              Motions.fadeIn,
            ]),
            exit: Motions.combine([
              Motions.rotate(startTurns: 0, endTurns: 1),
              Motions.fadeOut,
            ]),
          },
          child: FlutterLogo(
            size: 50,
          ),
        ),
        MotionText(
          text: 'Hello world',
          style: TextStyle(
            fontSize: 64,
            color: Colors.black,
            fontWeight: FontWeight.bold,
          ),
          characterMotion: {
            entrance: Motions.fadeFromTop(),
            exit: Motions.fadeToTop(),
          },
          reversedCharacterAnimation: [exit],
          wordMotion: {
            entrance: Motions.fadeIn,
            exit: Motions.fadeOut,
          },
        ),
      ],
    );
  }
}

组件

声明动画引用

首先,你需要声明场景中的各种动画序列作为全局对象。

const entrance = MontageAnimation(
  duration: Duration(seconds: 2),
);

const idle = MontageAnimation(
  duration: Duration(seconds: 3),
);

const exit = MontageAnimation(
  duration: Duration(seconds: 2),
);

Montage

蒙太奇作为运动组件的根配置。它接受一个专用控制器,用于触发动画。

class _HomeState extends State<Home> with TickerProviderStateMixin {
  MontageController? controller;

  @override
  void initState() {
    controller = MontageController(
      vsync: this,
      initialAnimation: entrance,
    );
    super.initState();
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Montage(
        controller: controller!,
        child: Scene(),
      ),
      floatingActionButton: FloatingActionButton(
        icon: Icon(Icons.video_call),
        onPressed: () {
          /// 播放这些动画序列
          controller!.play([
            entrance,
            exit,
            entrance,
            idle,
            exit,
          ]);
        },
      ),
    );
  }
}

Motion

核心组件,可以为每个从根Montage控制器播放的动画序列以不同的方式动画化子组件。

Motion(
    motion: {
        entrance: Motions.fadeIn,
        exit: Motions.fadeOut,
    },
    child: FlutterLogo(
        size: 50,
    ),
)

分段动画

如果你想逐步动画一组组件,可以使用Motion.staggered辅助方法。

Row(
    mainAxisSize: MainAxisSize.min,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
    ...Motion.staggered(
        children: [
            Text("FL"),
            Text("UT"),
            Text("TER"),
        ],
        motion: (child, i, forward, backward) {
            return {
                entrance: Motions.curved(
                    forward,
                        Motions.combine([
                            Motions.rotate(startTurns: -1, endTurns: 0),
                            Motions.fadeIn,
                            Motions.scale(begin: 3, end: 1)
                        ]),
                ),
                exit: Motions.curved(
                    backward,
                        Motions.combine([
                        Motions.rotate(startTurns: 0, endTurns: -1),
                        Motions.fadeOut,
                        Motions.scale(begin: 1, end: 3)
                    ]),
                ),
            };
        },
    )
    ],
),

动画

内置动画

一系列内置动画可以在motions.dart文件中找到。

自定义动画

动画只是一个基于当前Animation<double>和应被动画化的子组件的构建器。

Widget fadeIn(
  BuildContext context,
  MontageAnimation current,
  Animation<double> animation,
  Widget? child,
) {
    return FadeTransition(
        opacity: animation,
        child: child,
    );
}

更多关于Flutter图像合成插件montage的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图像合成插件montage的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


montage 是一个用于图像合成的 Flutter 插件,它允许你将多张图片合并成一张图片。这个插件通常用于创建图片拼贴、缩略图网格等场景。以下是如何在 Flutter 项目中使用 montage 插件的基本步骤。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 montage 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  montage: ^0.0.1  # 请检查最新版本

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

2. 导入插件

在你的 Dart 文件中导入 montage 插件。

import 'package:montage/montage.dart';

3. 使用 montage 进行图像合成

以下是一个简单的示例,展示如何使用 montage 插件将多张图片合成一张图片。

import 'package:flutter/material.dart';
import 'package:montage/montage.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;

class ImageMontageExample extends StatefulWidget {
  @override
  _ImageMontageExampleState createState() => _ImageMontageExampleState();
}

class _ImageMontageExampleState extends State<ImageMontageExample> {
  ui.Image? _montageImage;

  @override
  void initState() {
    super.initState();
    _createMontage();
  }

  Future<void> _createMontage() async {
    // 加载图片
    final image1 = await _loadImage('assets/image1.jpg');
    final image2 = await _loadImage('assets/image2.jpg');
    final image3 = await _loadImage('assets/image3.jpg');

    // 使用 montage 合成图片
    final montage = Montage();
    final Uint8List? result = await montage.createMontage(
      images: [image1, image2, image3],
      grid: [2, 2], // 2行2列的网格
      backgroundColor: Colors.white, // 背景颜色
      padding: 10.0, // 图片之间的间距
    );

    if (result != null) {
      final codec = await ui.instantiateImageCodec(result);
      final frame = await codec.getNextFrame();
      setState(() {
        _montageImage = frame.image;
      });
    }
  }

  Future<Uint8List> _loadImage(String assetPath) async {
    final ByteData data = await rootBundle.load(assetPath);
    return data.buffer.asUint8List();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Montage Example'),
      ),
      body: Center(
        child: _montageImage != null
            ? RawImage(
                image: _montageImage,
                fit: BoxFit.cover,
              )
            : CircularProgressIndicator(),
      ),
    );
  }
}

void main() => runApp(MaterialApp(
  home: ImageMontageExample(),
));

4. 解释代码

  • 加载图片:我们使用 _loadImage 方法从 assets 中加载图片,并将其转换为 Uint8List
  • 使用 montage 合成图片:我们创建了一个 Montage 实例,并调用 createMontage 方法,传入图片列表、网格布局、背景颜色和间距等参数。
  • 显示合成后的图片:合成后的图片被转换为 ui.Image,并在 RawImage 中显示。

5. 运行项目

确保你的 pubspec.yaml 文件中已经正确配置了 assets:

flutter:
  assets:
    - assets/image1.jpg
    - assets/image2.jpg
    - assets/image3.jpg
回到顶部