QML 的 OpacityMask
用于通过遮罩元素的 透明度(Alpha 通道) 裁剪源元素的可见区域,适用于创建不规则形状的 UI 元素(如圆形头像、波浪形进度条)或复杂视觉效果。以下是详细使用技巧和常见场景示例:
1. 基本用法
import QtQuick 2.15
import QtQuick.Effects 1.15 // 引入效果模块
Item {
width: 300
height: 300
// 源元素(被裁剪的内容)
Image {
id: sourceImage
source: "image.jpg"
visible: false // 隐藏源,仅用于遮罩输入
}
// 遮罩元素(定义可见区域)
Rectangle {
id: mask
width: 200
height: 200
radius: 100 // 圆形遮罩
visible: false // 隐藏遮罩元素
}
// 应用透明度遮罩
OpacityMask {
anchors.fill: parent
source: sourceImage // 源内容
maskSource: mask // 遮罩形状
}
}
关键属性:
source
:被遮罩的源元素(需隐藏,visible: false
)。maskSource
:定义裁剪形状的遮罩元素(透明度决定源元素的可见性)。invert
:设为true
时反转遮罩(显示原本透明的区域)。cached
:设为true
缓存遮罩结果,提升性能。
2. 常见应用场景
(1) 圆形头像
Image {
id: avatar
source: "user.png"
visible: false
}
OpacityMask {
width: 100
height: 100
source: avatar
maskSource: Rectangle { // 圆形遮罩
width: 100
height: 100
radius: 50
visible: false
}
}
(2) 渐变遮罩(文字淡出)
Text {
id: longText
text: "This is a long text that needs to fade out at the bottom..."
width: 200
wrapMode: Text.Wrap
visible: false
}
// 渐变遮罩(从上到下透明度从1到0)
Rectangle {
id: gradientMask
width: 200
height: 100
visible: false
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: 1.0; color: "transparent" }
}
}
OpacityMask {
source: longText
maskSource: gradientMask
}
(3) 动态遮罩(可拖动区域)
Item {
width: 400
height: 400
Image {
id: background
source: "map.jpg"
visible: false
}
// 可拖动的圆形遮罩
Rectangle {
id: dynamicMask
width: 100
height: 100
radius: 50
visible: false
x: mouseArea.mouseX - width/2
y: mouseArea.mouseY - height/2
}
OpacityMask {
source: background
maskSource: dynamicMask
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
}
3. 进阶技巧
(1) 结合其他特效(模糊+遮罩)
OpacityMask {
source: ShaderEffect { // 先模糊再遮罩
property variant src: Image { source: "image.jpg" }
layer.enabled: true
layer.effect: FastBlur { radius: 16 }
}
maskSource: Rectangle { // 星形遮罩
width: 200; height: 200
visible: false
Canvas { // 绘制星形路径
anchors.fill: parent
onPaint: {
var ctx = getContext("2d");
ctx.beginPath();
// ... 绘制星形路径
ctx.fillStyle = "white";
ctx.fill();
}
}
}
}
(2) 反转遮罩(显示外部区域)
OpacityMask {
source: Image { source: "image.jpg"; visible: false }
maskSource: Rectangle { // 中心透明的圆形
width: 200; height: 200
radius: 100
color: "white"
Rectangle { // 中心挖空
anchors.centerIn: parent
width: 50; height: 50
radius: 25
color: "transparent"
}
visible: false
}
invert: true // 反转遮罩,显示挖空的外部
}
(3) 动画遮罩(动态形状变化)
Rectangle {
id: animatingMask
width: 200; height: 200
visible: false
radius: width/2 * (0.5 + waveAnim.value) // 动态圆角
NumberAnimation {
id: waveAnim
target: animatingMask
property: "radius"
from: 0.1
to: 0.9
duration: 2000
loops: Animation.Infinite
running: true
}
}
OpacityMask {
source: Image { source: "texture.jpg"; visible: false }
maskSource: animatingMask
}
4. 性能优化
- 启用缓存:对静态遮罩设置
cached: true
。 - 简化遮罩元素:避免使用复杂
Canvas
或动态生成的遮罩。 - 降采样处理:缩小遮罩和源的纹理尺寸:
layer.textureSize: Qt.size(width/2, height/2)
5. 常见问题
(1) 遮罩不显示
- 检查
source
和maskSource
是否已正确隐藏(visible: false
)。 - 确认遮罩元素的 Alpha 通道非全透明(至少部分区域为可见)。
(2) 边缘锯齿
- 启用
layer.smooth: true
抗锯齿。 - 使用高分辨率遮罩或增加遮罩元素的
layer.textureSize
。
(3) 动态遮罩卡顿
- 减少遮罩元素的复杂度(如避免实时绘制
Canvas
)。 - 限制遮罩属性更新的频率(如节流动画帧率)。
总结
- 核心作用:通过遮罩的透明度通道控制源元素的可见区域。
- 关键属性:
source
(源内容)、maskSource
(遮罩形状)、invert
(反转遮罩)。 - 适用场景:不规则形状裁剪、动态区域显示、渐变过渡效果。
- 优化要点:简化遮罩结构、启用缓存、合理降采样。