如何在颤振中使用混合混合模式?

Posted

技术标签:

【中文标题】如何在颤振中使用混合混合模式?【英文标题】:How to use mix blend mode in flutter? 【发布时间】:2020-10-18 13:56:01 【问题描述】:

我尝试了似乎仅适用于颜色的混合模式,即 colorblendmode。有什么办法可以实现mix-blend-mode as of CSS?

  Stack(
        children: <Widget>[
          Image.asset(
            "asset/text.PNG",
            height: double.maxFinite,
            width: double.maxFinite,
            fit: BoxFit.fitHeight,
            color: Colors.red,
            colorBlendMode: BlendMode.multiply,
          ),
          Image.asset("asset/face.jpg",
              width: double.maxFinite,
              fit: BoxFit.fitHeight,
              color: Colors.red,
              colorBlendMode: BlendMode.multiply),
        ],
      ),

这会产生如下结果: The output of code above

我想得到什么 Output from CSS

【问题讨论】:

不知道。但也许您可以尝试使用 BlendMode. 的不同组合。我的意思是,不仅仅是乘法。另一种方法是尝试 OverlayPainter 和 BlendMode。 我想我有一个使用 RenderElements 和 BlendModes 的解决方案。应该稍后出来。 【参考方案1】:

试试ShaderMask。BlendModes

使用示例:

import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;

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

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

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


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


class _MyHomePageState extends State<MyHomePage> 
  Future<ui.Image> loadUiImage(String imageAssetPath) async 
    final data = await rootBundle.load(imageAssetPath);
    final completer = Completer<ui.Image>();
    ui.decodeImageFromList(Uint8List.view(data.buffer), completer.complete);
    return completer.future;
  

  @override
  Widget build(BuildContext context) 
    return FutureBuilder<ui.Image>(
        future: loadUiImage('assets/cara_img.png'),
        builder: (context, img) 
          return img.hasData
              ? ShaderMask(
                  blendMode: BlendMode.colorDodge,
                  shaderCallback: (bounds) => ImageShader(
                    img.data,
                    TileMode.clamp,
                    TileMode.clamp,
                    Matrix4.identity().storage,
                  ),
                  child: Image.asset('assets/code.png'),
                )
              : Container(
                  color: Colors.red,
                  height: 100,
                  width: 100,
                  child: Text('loading'),
                );
        );
  

code.png: cara_img.png:

结果:

【讨论】:

这是一个很棒的解决方案,但它有点笨重,而且您必须异步加载图像。为什么不使用 RenderObjects?【参考方案2】:

使用 RenderProxyBox 和一些绘画,我能够在 CSS 网站上重新创建确切的示例,而无需在 Flutter 代码中异步加载图像。

使用 CSS 的图像(左)与使用 Flutter 的图像(右)。

Read the article I wrote about this here

首先,创建一个 BlendMask SingleChildRenderObject,它创建一个名为 RenderBlendMask 的 RenderProxyBox 渲染对象。孩子使用 BlendMode 和不透明度进行绘制。

import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

class BlendMask extends SingleChildRenderObjectWidget 
  final BlendMode blendMode;
  final double opacity;

  BlendMask(
    @required this.blendMode,
    this.opacity = 1.0,
    Key key,
    Widget child,
  ) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(context) 
    return RenderBlendMask(blendMode, opacity);
  

  @override
  void updateRenderObject(BuildContext context, RenderBlendMask renderObject) 
    renderObject.blendMode = blendMode;
    renderObject.opacity = opacity;
  


class RenderBlendMask extends RenderProxyBox 
  BlendMode blendMode;
  double opacity;

  RenderBlendMask(this.blendMode, this.opacity);

  @override
  void paint(context, offset) 
    context.canvas.saveLayer(
        offset & size,
        Paint()
          ..blendMode = blendMode
          ..color = Color.fromARGB((opacity * 255).round(), 255, 255, 255));

    super.paint(context, offset);

    context.canvas.restore();
  

现在要混合两个小部件(不限于图像),只需使用堆栈将要混合的小部件添加到另一个上方,然后将其包装在 BlendMode 中。

class ImageMixer extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: SizedBox.expand(
          child: Stack(
        children: [
          SizedBox.expand(
            child: Image.asset(
              'images/sky.jpg',
            ),
          ),
          BlendMask(
            opacity: 1.0,
            blendMode: BlendMode.softLight,
            child: SizedBox.expand(
              child: Image.asset(
                'images/monkey.jpg',
              ),
            ),
          ),
        ],
      )),
    );
  

生成上面的图像,它的工作方式与 CSS 示例完全相同。

【讨论】:

没问题@ReikoDev。如果您有兴趣,我可能应该链接到我写的关于它的文章。 wilsonwilson.dev/articles/css-style-blending-using-flutter 再次感谢@Wilson!我正在玩画布,这很有帮助!一个问题,当你有一个自定义布局(例如在 Illustrator 上制作)时,像 ibb.co/WV3JxZd 这样的东西,你使用哪种方法让它在颤振上变得真实? @ReikoDev 哇哦,很多很多的定制油漆。不过,我不相信用颤振构建一切是一个现实或好主意。对于星星、窗帘、横幅以及可能的容器之类的东西,最好使用原始设计文件。对于诸如进度条之类的反应组件,您可以安全地使用自定义油漆:D 哦,我明白了!再次感谢威尔逊!!

以上是关于如何在颤振中使用混合混合模式?的主要内容,如果未能解决你的问题,请参考以下文章

UE4材质混合模式bate0117

chrome中的Chrome css3混合混合模式错误

SKEmitterNode 如何在不同背景下使用混合模式“添加”保持相同的效果

在 Android 中使用 ColorMatrixFilter 减去混合模式?

Three.js 中的硬光材质混合模式?

Chrome 中的混合模式问题