QML 内阴影效果
QML Inner Shadow effect
我想在 QML
中创建一个带有内部阴影的矩形,类似于 Photoshop
所做的:
QML
有 InnerShadow
但我无法实现这种效果。我得到的最接近的是这个
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id: root
width: 300
height: 300
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 100
height: 100
color: "grey"
}
InnerShadow {
anchors.fill: root
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: root
}
}
这是我从 this post 那里得到的想法。但是,此示例仅在 root
的大小明显大于 myRectangle
的情况下才有效,而我不希望这样。我需要例如一个 200x10
正方形,其中阴影均匀分布在矩形的边缘。我为 InnerShadow
属性尝试了各种值,但我无法接近我想要的效果。
这可以使用 QML
实现吗?
"correct"方法-需要引号-使用效果应该是这个:
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id: root
width: 300
height: 300
Item {
id: src
anchors.fill: parent
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 100
height: 100
color: "grey"
}
}
InnerShadow {
anchors.fill: src
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: src
}
}
如您所见,它与另一个问题中提出的解决方案略有不同。使用此代码,您仍然需要保留 2 个像素才能产生效果,从而产生白色边框(或任何背景颜色)。通过将 root
更改为 Rectangle
.
可以轻松解决此问题
最终示例解决方案如下。显然,您可以提取 root
组件(和相关的子组件)并将其放在 Component
或不同的 .qml
文件中供以后使用。
import QtQuick 2.4
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
Window {
width: 200
height: 20
visible: true
Rectangle { // was Item
id: root
anchors.fill: parent
color: "grey"
Item {
id: src
anchors.fill: parent
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: root.width - 2
height: root.height - 2
color: "lightgrey"
}
}
InnerShadow {
anchors.fill: src
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: src
}
}
}
最终代码示例的结果 window:
InnerShadow 元素类似于 QML 中的大多数图形效果元素和 GLSL 着色器,它查找边缘的方式是寻找透明和非透明之间的过渡。如果将滤镜应用于完全实心的图形元素,它不会找到任何边缘,因此也不会找到阴影。这与 Photoshop 滤镜的工作方式完全相同,它还通过扫描从透明到不透明的边缘来找到边缘(如您提供的示例所示)。它可以将图形区域的边缘视为隐式边缘,但这会大大限制可用性。这是 InnerShadow. Which again uses FastInnerShadow or GaussianInnerShadow 的来源,具体取决于 fast 属性。
如果您想要一个可以添加到现有元素的实现,而不必关心透明和非透明边缘之间的过渡,您可以使用这个:
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 300
height: 300
color: "#AAAAAA"
}
Item {
id: _innerShadow
property var shadowSource: myRectangle
property var color: "#B0000000"
anchors.fill: shadowSource
Item {
id: _shadowMarker
//width: source.width+1; height: source.height+1
anchors.fill: parent;
anchors.margins: -10
ColorOverlay {
anchors.fill: _shadowMarker;
anchors.margins: 10
source: _innerShadow.shadowSource
color: "#00000000"
}
visible: false
}
InnerShadow {
anchors.fill: _shadowMarker
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: _innerShadow.color
smooth: true
source: _shadowMarker
}
}
这是我的解决方案
GoodInnerShadow.qml
///
/// Same as InnerShadow QML type, with the following differences
///
/// InnerShadow requires transparent space to be surrounding the
/// item that you want to make an inner shadow for. GoodInnerShadow
/// does not require this.
///
/// InnerShadow draws the source with the shadow. GoodInnerShadow
/// draws just the shadow
///
import QtQuick 2.15
import QtGraphicalEffects 1.0
Item {
id: root
anchors.centerIn: source
width: source.width
height: source.height
required property var source
property color color: "#50ffffff"
property double radius: 12
property double spread: .8
Item{
id: sourceMaskWithPadding
visible: false
anchors.centerIn: parent
width: root.source.width + shadowOfInverse.samples * 2
height: root.source.height + shadowOfInverse.samples * 2
OpacityMask {
id: sourceMask
anchors.centerIn: parent
width: root.source.width
height: root.source.height
maskSource: root.source
source: root.source
}
}
Rectangle {
id: coloredRect
visible: false
color: root.color
anchors.fill: sourceMaskWithPadding
}
OpacityMask {
id: sourceInverse
visible: false
anchors.fill: coloredRect
source: coloredRect
maskSource: sourceMaskWithPadding
invert: true
}
DropShadow {
id: shadowOfInverse
visible: false
anchors.fill: sourceInverse
source: sourceInverse
radius: root.radius
samples: radius * 2 + 1
color: root.color
spread: root.spread
}
OpacityMask {
id: sourceInnerShadow
anchors.fill: sourceMaskWithPadding
maskSource: sourceMaskWithPadding
source: shadowOfInverse
}
}
示例用法
import QtQuick 2.15
Item {
width: 400
height: 300
Rectangle {
id: myRect
anchors.centerIn: parent
width: 300
height: 100
color: "lightgray"
}
GoodInnerShadow {
source: myRect
color: "#aa000000"
spread: .5
radius: 16
}
}
结果
我想在 QML
中创建一个带有内部阴影的矩形,类似于 Photoshop
所做的:
QML
有 InnerShadow
但我无法实现这种效果。我得到的最接近的是这个
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id: root
width: 300
height: 300
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 100
height: 100
color: "grey"
}
InnerShadow {
anchors.fill: root
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: root
}
}
这是我从 this post 那里得到的想法。但是,此示例仅在 root
的大小明显大于 myRectangle
的情况下才有效,而我不希望这样。我需要例如一个 200x10
正方形,其中阴影均匀分布在矩形的边缘。我为 InnerShadow
属性尝试了各种值,但我无法接近我想要的效果。
这可以使用 QML
实现吗?
"correct"方法-需要引号-使用效果应该是这个:
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
id: root
width: 300
height: 300
Item {
id: src
anchors.fill: parent
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 100
height: 100
color: "grey"
}
}
InnerShadow {
anchors.fill: src
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: src
}
}
如您所见,它与另一个问题中提出的解决方案略有不同。使用此代码,您仍然需要保留 2 个像素才能产生效果,从而产生白色边框(或任何背景颜色)。通过将 root
更改为 Rectangle
.
最终示例解决方案如下。显然,您可以提取 root
组件(和相关的子组件)并将其放在 Component
或不同的 .qml
文件中供以后使用。
import QtQuick 2.4
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
Window {
width: 200
height: 20
visible: true
Rectangle { // was Item
id: root
anchors.fill: parent
color: "grey"
Item {
id: src
anchors.fill: parent
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: root.width - 2
height: root.height - 2
color: "lightgrey"
}
}
InnerShadow {
anchors.fill: src
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: "#b0000000"
smooth: true
source: src
}
}
}
最终代码示例的结果 window:
InnerShadow 元素类似于 QML 中的大多数图形效果元素和 GLSL 着色器,它查找边缘的方式是寻找透明和非透明之间的过渡。如果将滤镜应用于完全实心的图形元素,它不会找到任何边缘,因此也不会找到阴影。这与 Photoshop 滤镜的工作方式完全相同,它还通过扫描从透明到不透明的边缘来找到边缘(如您提供的示例所示)。它可以将图形区域的边缘视为隐式边缘,但这会大大限制可用性。这是 InnerShadow. Which again uses FastInnerShadow or GaussianInnerShadow 的来源,具体取决于 fast 属性。
如果您想要一个可以添加到现有元素的实现,而不必关心透明和非透明边缘之间的过渡,您可以使用这个:
Rectangle {
id: myRectangle
anchors.centerIn: parent
width: 300
height: 300
color: "#AAAAAA"
}
Item {
id: _innerShadow
property var shadowSource: myRectangle
property var color: "#B0000000"
anchors.fill: shadowSource
Item {
id: _shadowMarker
//width: source.width+1; height: source.height+1
anchors.fill: parent;
anchors.margins: -10
ColorOverlay {
anchors.fill: _shadowMarker;
anchors.margins: 10
source: _innerShadow.shadowSource
color: "#00000000"
}
visible: false
}
InnerShadow {
anchors.fill: _shadowMarker
cached: true
horizontalOffset: 0
verticalOffset: 0
radius: 16
samples: 32
color: _innerShadow.color
smooth: true
source: _shadowMarker
}
}
这是我的解决方案
GoodInnerShadow.qml
///
/// Same as InnerShadow QML type, with the following differences
///
/// InnerShadow requires transparent space to be surrounding the
/// item that you want to make an inner shadow for. GoodInnerShadow
/// does not require this.
///
/// InnerShadow draws the source with the shadow. GoodInnerShadow
/// draws just the shadow
///
import QtQuick 2.15
import QtGraphicalEffects 1.0
Item {
id: root
anchors.centerIn: source
width: source.width
height: source.height
required property var source
property color color: "#50ffffff"
property double radius: 12
property double spread: .8
Item{
id: sourceMaskWithPadding
visible: false
anchors.centerIn: parent
width: root.source.width + shadowOfInverse.samples * 2
height: root.source.height + shadowOfInverse.samples * 2
OpacityMask {
id: sourceMask
anchors.centerIn: parent
width: root.source.width
height: root.source.height
maskSource: root.source
source: root.source
}
}
Rectangle {
id: coloredRect
visible: false
color: root.color
anchors.fill: sourceMaskWithPadding
}
OpacityMask {
id: sourceInverse
visible: false
anchors.fill: coloredRect
source: coloredRect
maskSource: sourceMaskWithPadding
invert: true
}
DropShadow {
id: shadowOfInverse
visible: false
anchors.fill: sourceInverse
source: sourceInverse
radius: root.radius
samples: radius * 2 + 1
color: root.color
spread: root.spread
}
OpacityMask {
id: sourceInnerShadow
anchors.fill: sourceMaskWithPadding
maskSource: sourceMaskWithPadding
source: shadowOfInverse
}
}
示例用法
import QtQuick 2.15
Item {
width: 400
height: 300
Rectangle {
id: myRect
anchors.centerIn: parent
width: 300
height: 100
color: "lightgray"
}
GoodInnerShadow {
source: myRect
color: "#aa000000"
spread: .5
radius: 16
}
}
结果