显示半个小部件(一个图标)

huangapple go评论78阅读模式
英文:

Show half a widget (an icon)

问题

我想实现与下面这个类似的效果:

显示半个小部件(一个图标)

这个想法是在灰色的图标上完全显示一个图标,然后在其上方显示相同的图标,但颜色不同,并且只在屏幕上显示部件的一部分。我尝试使用StackAlignheightFactor)来实现,但效果不好。

有什么想法吗?

编辑: 这是我尝试的代码:

class TestWidget extends StatefulWidget {
  const TestWidget({Key? key});

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

class _TestWidgetState extends State<TestWidget> {
  GlobalKey aKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.grey[200],
        child: Align(
          alignment: const Alignment(-0.85, -0.85),
          child: Wrap(children: [
            Stack(
              children: [
                Center(
                    child: Icon(
                        key: aKey,
                        icon: Icons.thunderstorm,
                        color: Colors.blueGrey,
                        size: 100)),
                Column(
                  children: [
                    LayoutBuilder(builder: (context, _) {
                      RenderBox renderbox =
                          aKey.currentContext!.findRenderObject() as RenderBox;

                      return SizedBox(height: renderbox.size.height * 0.25);
                    }),
                    const ClipRect(
                        child: Align(
                      heightFactor:
                          0.5, // Set this to 0.8 to see the displaced, unmatching image.
                      child: Icon(Icons.thunderstorm,
                          color: Colors.red, size: 100),
                    ))
                  ],
                )
              ],
            )
          ]),
        ));
  }
}

分别是heightFactor为0.5和0.8时的输出:

显示半个小部件(一个图标)
显示半个小部件(一个图标)

英文:

I would like to achive an effect similar to the next one:

显示半个小部件(一个图标)

The idea is to have a fully displayed Icon in grey, and then in top of it the same Icon but in another color and only showing on the screen a percentage of the widget on top. I've tried to do it with Stack and Align (heightFactor) but nothing worked well.

Any ideas?

EDIT: Here it's the code I tried:

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

  @override
  State&lt;TestWidget&gt; createState() =&gt; _TestWidgetState();
}

class _TestWidgetState extends State&lt;TestWidget&gt; {
  GlobalKey aKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.grey[200],
        child: Align(
          alignment: const Alignment(-0.85, -0.85),
          child: Wrap(children: [
            Stack(
              children: [
                Center(
                    child: Icon(
                        key: aKey,
                        Symbols.thunderstorm,
                        color: Colors.blueGrey,
                        size: 100)),
                Column(
                  children: [
                    LayoutBuilder(builder: (context, _) {
                      RenderBox renderbox =
                          aKey.currentContext!.findRenderObject() as RenderBox;

                      return SizedBox(height: renderbox.size.height * 0.25);
                    }),
                    const ClipRect(
                        child: Align(
                      heightFactor:
                          0.5, // Set this to 0.8 to see the displaced, unmatching image.
                      child: Icon(Symbols.thunderstorm,
                          color: Colors.red, size: 100),
                    ))
                  ],
                )
              ],
            )
          ]),
        ));
  }
}

These are the outputs for 0.5 and 0.8 heightFactor, respectively:

显示半个小部件(一个图标)
显示半个小部件(一个图标)

答案1

得分: 0

受到@pskink答案的启发,我想出了这个可行的示例:

class TestWidget extends StatefulWidget {
  const TestWidget({Key? key});

  @override
  State<TestWidget> createState() => _TestWidgetState();
}

class _TestWidgetState extends State<TestWidget> {
  GlobalKey aKey = GlobalKey();

  double percent = 0.3;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.grey[200],
      child: Align(
        alignment: const Alignment(-0.85, -0.85),
        child: Wrap(
          children: [
            Stack(
              children: [
                Center(
                  child: Icon(
                    key: aKey,
                    Icons.thunderstorm,
                    color: Colors.blueGrey,
                    size: 100,
                  ),
                ),
                Column(
                  children: [
                    LayoutBuilder(builder: (context, _) {
                      RenderBox renderbox =
                          aKey.currentContext!.findRenderObject() as RenderBox;

                      return SizedBox(
                        height: renderbox.size.height * (1 - percent),
                      );
                    }),
                    ClipRect(
                      child: Align(
                        heightFactor: percent,
                        alignment: Alignment.bottomCenter,
                        child: const Icon(
                          Icons.thunderstorm,
                          color: Colors.red,
                          size: 100,
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

这个示例可以按预期工作。之所以能够实现这个效果,是因为如果你将有颜色的小部件对齐到顶部,heightFactor 会从顶部开始裁剪。你只需要将新的裁剪小部件插入到一个带有 SizedBox 的 Column 中,SizedBox 的高度为你从有颜色的小部件中减少的高度。

我无法弄清楚如何配置 @pskink 建议的 Rect 对象,如果他能提供一个详细的代码,完善这个解决方案,将不胜感激。

英文:

Inspired by @pskink's answer, I came up with this working example:

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

  @override
  State&lt;TestWidget&gt; createState() =&gt; _TestWidgetState();
}

class _TestWidgetState extends State&lt;TestWidget&gt; {
  GlobalKey aKey = GlobalKey();

  double percent = 0.3;

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.grey[200],
        child: Align(
          alignment: const Alignment(-0.85, -0.85),
          child: Wrap(children: [
            Stack(
              children: [
                Center(
                    child: Icon(
                        key: aKey,
                        Symbols.thunderstorm,
                        color: Colors.blueGrey,
                        size: 100)),
                Column(
                  children: [
                    LayoutBuilder(builder: (context, _) {
                      RenderBox renderbox =
                          aKey.currentContext!.findRenderObject() as RenderBox;

                      return SizedBox(
                          height: renderbox.size.height * (1 - percent));
                    }),
                    ClipRect(
                      child: Align(
                          heightFactor: percent,
                          alignment: Alignment.bottomCenter,
                          child: const Icon(Symbols.thunderstorm,
                              color: Colors.red, size: 100)),
                    )
                  ],
                )
              ],
            )
          ]),
        ));
  }
}

Which works as desired. The reason for it is because if you align the coloured widget to the top, the heightFactor cuts starting from there. You only need to insert the new cut widget in a Column with a SizedBox with the height you loose from the coloured one.

I couldn't figure out how to configure the Rect object @pskink suggested, and it would be appreciated if he could give a detailed code with his full solution to complement this one.

答案2

得分: 0

你可以使用ShaderMask小部件来使用gradient颜色对图标进行遮罩,并使用stop属性进行突变的颜色变化。

我创建了这个演示,你可以看到一个例子。运行它并点击图标以查看变化。

英文:

You can use ShaderMask widget to mask the icon with a gradient color, and use the stop property for the sudden color change.

I created this demo so you can see an example. Run it and click on the icon to see the changes.

答案3

得分: -1

一种实现方法是使用一个Stack和两个图标,将一个图标放在另一个图标上方,并使用ClipRect将上方图标切割成一半,显示底部一半的图标。以下是一个示例:

Container(
  width: 100,
  child: Stack(
    children: [
      Icon(
        Icons.bolt,
        size: 100,
        color: Colors.grey,
      ),
      ClipRect(
        child: Align(
          alignment: Alignment.topCenter,
          heightFactor: 0.5,
          child: Icon(
            Icons.bolt,
            size: 100,
            color: Colors.yellow,
          ),
        ),
      ),
    ],
  ),
)
英文:

One way to achieve that is using an Stack and two icons, placing one icon above another, and using a ClipRect to cut superior's icons in half, showing the bottom half of the icon behind. Here's an example:

Container(
	width: 100,
	child: Stack(
	  children: [
		Icon(
		  Icons.bolt,
		  size: 100,
		  color: Colors.grey,
		),
		ClipRect(
		  child: Align(
			alignment: Alignment.topCenter,
			heightFactor: 0.5,
			child: Icon(
			  Icons.bolt,
			  size: 100,
			  color: Colors.yellow,
			),
		  ),
		),
	  ],
	))

huangapple
  • 本文由 发表于 2023年8月8日 20:11:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76859440.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定