ShaderMask LinearGradient's stops strange behavior

北城以北 提交于 2021-01-28 12:30:40

问题


I want to fade both side (edges) of a content.

I use a ShaderMask along with a LinearGradient, it works great except that I don't understand why my stops are not centered correctly, I use stops: [0.0, 0.05, 0.95, 1.0] so that it should be faded 0.05 on each side, but I get the following (I added a Container gradient with same configuration for comparison):

With debug paint mode :

I use exactly the same stops for the Container and for the ShaderMask but get different results.

Of course I can try different stops values for the ShaderMask gradient until I got it centered but it seems like a hack.

Someone can explain ?

Here's the code if anyone want to give it a try :

return Container(
  height: 200,
  child: Column(
    children: <Widget>[
      Expanded(
        child: ShaderMask(
          blendMode: BlendMode.modulate,
          shaderCallback: (Rect bounds) {
            return LinearGradient(
              begin: Alignment.centerLeft,
              end: Alignment.centerRight,
              colors: <Color>[Colors.transparent, Colors.white, Colors.white, Colors.transparent],
              stops: [0.0, 0.05, 0.95, 1.0],
              tileMode: TileMode.clamp,
            ).createShader(bounds);
          },
          child: Container(
            color: Colors.blue,
            child: ListView(
              children: <Widget>[
                Text(
                  "I'm a ShaderMask and I don't understand why my gradient don't behave like container's gradient. I'm a ShaderMask and I don't understand why my gradient don't behave like container's gradient.",
                  textAlign: TextAlign.justify,
                )
              ],
            ),
          ),
        ),
      ),
      Expanded(
        child: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.centerLeft,
              end: Alignment.centerRight,
              colors: [Colors.transparent, Colors.blue, Colors.blue, Colors.transparent],
              stops: [0.0, 0.05, 0.95, 1.0],
              tileMode: TileMode.clamp,
            ),
          ),
          child: ListView(
            children: <Widget>[
              Text(
                "I'm a Container and I don't understand why ShaderMask's gradient don't behave like mine. I'm a Container and I don't understand why ShaderMask's gradient don't behave like mine.",
                textAlign: TextAlign.justify,
              )
            ],
          ),
        ),
      )
    ],
  ),
);

I got the same result using FractionalOffset instead of Alignment.centerRight and Alignment.centerRight.


回答1:


shaderCallback creates a Shader for a given Rect, and the Rect coordinates are relative to a given origin.

The shader callback is called with the current size of the child so that it can customize the shader to the size and location of the child.

It means we have to create the shader with a Rect based on the size of the child widget with no offset (basically the bounds passed to shaderCallback are in global coordinates while createShader is waiting for a local Rect).

So a simple solution is to create a new Rect with the right origin (offset) and bounds : createShader(Rect.fromLTRB(0, 0, bounds.width, bounds.height)).

Or a more sexy shorthand : createShader(Offset.zero & bounds.size) :

shaderCallback: (Rect bounds) {
  return LinearGradient(
    begin: Alignment.centerLeft,
    end: Alignment.centerRight,
    colors: <Color>[Colors.transparent, Colors.blue, Colors.blue, Colors.transparent],
    stops: [0.0, 0.04, 0.96, 1.0],
    tileMode: TileMode.clamp,
  ).createShader(Offset.zero & bounds.size);
},

Credits to pskink !



来源:https://stackoverflow.com/questions/59705860/shadermask-lineargradients-stops-strange-behavior

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!