Flutter着色器快照插件flutter_shader_snap的使用

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

Flutter着色器快照插件 flutter_shader_snap 的使用

flutter_shader_snap 是一个用于创建类似于“灭霸响指”效果的简单Flutter插件。它提供了两种主要的效果:分裂(split)和烟雾(smoke)。下面是该插件的详细使用方法。

插件介绍

Split Effect Smoke Effect

开始使用

1. 添加依赖

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

dependencies:
  flutter_shader_snap: latest version

2. 添加着色器

pubspec.yaml 文件中添加相应的着色器文件路径:

flutter:
  shaders:
    - packages/flutter_shader_snap/shaders/split_snap_effect_shader.glsl # 如果使用 SnapShaderType.split (默认)
    - packages/flutter_shader_snap/shaders/split_reversed_snap_effect_shader.glsl # 如果使用 SnapShaderType.splitReversed
    - packages/flutter_shader_snap/shaders/smoke_snap_effect_shader.glsl # 如果使用 SnapShaderType.smoke

3. 创建并使用 AnimationController

创建一个 AnimationController 并将其传递给 SnapShader 小部件:

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late final _controller = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 5),
  );

  @override
  Widget build(BuildContext context) {
    return SnapShader(
      controller: _controller,
      child: AnyWidget(), // 替换为你要应用效果的任何小部件
    );
  }
}

性能优化

着色器仅在动画运行时应用于子小部件,因此不会影响应用程序的整体性能。为了进一步优化,可以使用 AnimatedSampler 来确保只在需要时应用着色器。

builder: (context, child) => controller.value == 0
    ? child!
    : AnimatedSampler

完整示例 Demo

以下是一个完整的示例,展示了如何使用 flutter_shader_snap 插件来实现分裂和烟雾效果,并允许用户通过按钮控制这些效果。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_shader_snap/flutter_shader_snap.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Shader Snap DEMO',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late final _controller = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 5),
  );
  late final _controller2 = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 5),
  );
  int _counter = 0;
  int _index = 0;
  var _snapShaderType = SnapShaderType.split;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  void initState() {
    super.initState();
    _controller2.addStatusListener((status) async {
      if (status != AnimationStatus.completed || _controller2.value == 0) return;
      await Future.delayed(const Duration(seconds: 3));
      _controller2.animateBack(0, duration: const Duration(seconds: 1));
    });

    Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _index++;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return SnapShader(
      controller: _controller2,
      child: Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: const Text('Flutter Shader Snap DEMO'),
        ),
        body: SafeArea(
          child: Center(
            child: Column(
              children: [
                const Spacer(),
                SnapShader(
                  controller: _controller,
                  snapShaderType: _snapShaderType,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        'You have pushed the button this many times:',
                        style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: Colors.green),
                      ),
                      Text(
                        '$_counter',
                        style: Theme.of(context).textTheme.headlineMedium,
                      ),
                      const SizedBox(height: 8),
                      AnimatedContainer(
                        duration: const Duration(seconds: 1),
                        width: 100,
                        height: 100,
                        color: Colors.primaries[_index % Colors.primaries.length],
                      ),
                      const SizedBox(height: 8),
                      const Text('Use split (on) or smoke (off) shader'),
                      ...SnapShaderType.values.map(
                        (e) => GestureDetector(
                          onTap: () => setState(() => _snapShaderType = e),
                          child: Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Row(
                              children: [
                                Radio(
                                  groupValue: _snapShaderType,
                                  value: e,
                                  onChanged: (value) => setState(() => _snapShaderType = e),
                                ),
                                Text(e.toString().split('.').last),
                              ],
                            ),
                          ),
                        ),
                      ),
                      Align(
                        alignment: Alignment.centerRight,
                        child: Container(
                          width: 100,
                          height: 100,
                          margin: const EdgeInsets.only(right: 8, bottom: 50),
                          decoration: BoxDecoration(
                            color: Colors.primaries[(_index + 5) % Colors.primaries.length],
                            shape: BoxShape.circle,
                          ),
                        ),
                      )
                    ],
                  ),
                ),
                Slider(
                  value: _controller.value,
                  onChanged: (value) => _controller.value = value,
                ),
                const Spacer(),
                ElevatedButton(
                  onPressed: () => _controller.forward(),
                  child: const Text('Snap!'),
                ),
                const SizedBox(height: 8),
                ElevatedButton(
                  onPressed: () => _controller.stop(canceled: false),
                  child: const Text('Pause'),
                ),
                const SizedBox(height: 8),
                ElevatedButton(
                  onPressed: () => _controller.reset(),
                  child: const Text('Reset'),
                ),
                const SizedBox(height: 8),
                ElevatedButton(
                  onPressed: () => _controller2.forward(),
                  child: const Text('Snap EVERYTHING!'),
                ),
                const SizedBox(height: 8),
              ],
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

这个示例展示了如何使用 SnapShader 小部件来应用分裂或烟雾效果,并且可以通过按钮控制动画的播放、暂停和重置。此外,还展示了如何动态切换不同的着色器类型。


更多关于Flutter着色器快照插件flutter_shader_snap的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter着色器快照插件flutter_shader_snap的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用flutter_shader_snap插件的示例代码。这个插件允许你使用自定义的GLSL着色器并在Flutter应用中实时预览它们。

1. 添加依赖

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

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

2. 导入插件

在你的Dart文件中导入插件:

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

3. 编写自定义着色器

创建一个GLSL着色器文件,例如simple_shader.glsl

// simple_shader.glsl
precision mediump float;

uniform sampler2D u_texture;
uniform vec4 u_color;

varying vec2 v_texCoord;

void main() {
  vec4 texColor = texture2D(u_texture, v_texCoord);
  gl_FragColor = texColor * u_color;
}

4. 使用ShaderSnapWidget

在你的Flutter应用中,使用ShaderSnapWidget来加载和显示你的着色器:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Shader Snap Demo'),
        ),
        body: ShaderSnapDemo(),
      ),
    );
  }
}

class ShaderSnapDemo extends StatefulWidget {
  @override
  _ShaderSnapDemoState createState() => _ShaderSnapDemoState();
}

class _ShaderSnapDemoState extends State<ShaderSnapDemo> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ShaderSnapWidget(
        shaderSource: {
          'vertex': '''
          attribute vec4 a_position;
          attribute vec2 a_texCoord;
          uniform mat4 u_matrix;
          varying vec2 v_texCoord;
          void main() {
            gl_Position = u_matrix * a_position;
            v_texCoord = a_texCoord;
          }
          ''',
          'fragment': '''
          precision mediump float;
          uniform sampler2D u_texture;
          uniform vec4 u_color;
          varying vec2 v_texCoord;
          void main() {
            vec4 texColor = texture2D(u_texture, v_texCoord);
            gl_FragColor = texColor * u_color;
          }
          '''
        }, // 你可以在这里直接写GLSL代码,或者从文件加载
        uniforms: {
          'u_color': [1.0, 0.5, 0.5, 1.0], // 例如,设置颜色为粉红色
        },
        texture: NetworkImage('https://example.com/path/to/your/image.jpg'), // 使用网络图片作为纹理
      ),
    );
  }
}

5. 运行应用

确保你已经连接了一个Flutter设备或启动了Flutter模拟器,然后运行你的Flutter应用:

flutter run

以上代码演示了如何在Flutter中使用flutter_shader_snap插件来加载和显示自定义的GLSL着色器。你可以根据需要修改着色器代码和uniforms来实现不同的视觉效果。

回到顶部