如何在 flutter 中使用 mix 混合模式?

How to use mix blend mode in flutter?

我已经尝试过似乎只适用于颜色的混合模式,即 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

尝试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:

结果:

使用 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 示例完全相同。