由于该模块,Qt 5 存在内置的官方解决方案QtGraphicalEffects
,我很惊讶地发现没有人提供如此简单的解决方案。如果您的目标QtGraphicalEffects
是 Qt 6.x 不幸被弃用,那么请跳到答案的第二部分,该部分提出了一个独立于QtGraphicalEffects
.
QtGraphicalEffects
解决方案
其他影响之一OpacityMask
是用于此目的的类型。Image
这个想法是用Rectangle
具有正确设置的 a来掩盖源radius
。这是使用分层的最简单示例:
Image {
id: img
property bool rounded: true
property bool adapt: true
layer.enabled: rounded
layer.effect: OpacityMask {
maskSource: Item {
width: img.width
height: img.height
Rectangle {
anchors.centerIn: parent
width: img.adapt ? img.width : Math.min(img.width, img.height)
height: img.adapt ? img.height : width
radius: Math.min(width, height)
}
}
}
}
adapt
这个最小的代码对方形图像产生了很好的结果,但它也通过变量考虑了非方形图像。通过将标志设置为false
生成的蒙版将始终是一个圆圈,无论图像大小如何。这是可能的,因为使用了外部Item
填充源并允许真正的蒙版(内部Rectangle
)的大小可以随意调整。如果您只是针对填充源的遮罩,则显然可以摆脱外部Item
,而不管其纵横比如何。
这是一张可爱的猫图片,正方形格式(左),非正方形格式adapt: true
(中心),最后是非正方形格式和adapt: false
(右):
该解决方案的实现细节与另一个不错的答案中基于着色器的答案非常相似(cfr.OpacityMask
可以在此处找到该解决方案的 QML 源代码-SourceProxy
只需返回一个格式良好的内容ShaderEffectSource
来提供效果)。
无深度解决方案
如果您不想 -或不能- 依赖于QtGraphicalEffects
模块(好吧,OpacityMask.qml
实际上是存在的),您可以使用着色器重新实现效果。除了已经提供的解决方案之外,另一种方法是使用step
,smoothstep
和fwidth
函数。这是代码:
import QtQuick 2.5
Image {
id: image
property bool rounded: true
property bool adapt: true
layer.enabled: rounded
layer.effect: ShaderEffect {
property real adjustX: image.adapt ? Math.max(width / height, 1) : 1
property real adjustY: image.adapt ? Math.max(1 / (width / height), 1) : 1
fragmentShader: "
#ifdef GL_ES
precision lowp float;
#endif // GL_ES
varying highp vec2 qt_TexCoord0;
uniform highp float qt_Opacity;
uniform lowp sampler2D source;
uniform lowp float adjustX;
uniform lowp float adjustY;
void main(void) {
lowp float x, y;
x = (qt_TexCoord0.x - 0.5) * adjustX;
y = (qt_TexCoord0.y - 0.5) * adjustY;
float delta = adjustX != 1.0 ? fwidth(y) / 2.0 : fwidth(x) / 2.0;
gl_FragColor = texture2D(source, qt_TexCoord0).rgba
* step(x * x + y * y, 0.25)
* smoothstep((x * x + y * y) , 0.25 + delta, 0.25)
* qt_Opacity;
}"
}
}
与第一种方法类似,rounded
添加adapt
属性以控制效果的视觉外观,如上所述。