View Masking
Besides the view clipping functionality provided by the library there is another approach for creating a visually complex designs where precise control over a view's content visibility is required. We call it view masking. It allows us to reveal or hide parts of a view based on the transparency or opacity of a specified mask image or gradient. This can be particularly useful for applying intricate clipping paths, creating fade effects, or overlaying images with custom shapes. The alpha channel of an image or gradient is used for masking the view. Below are the list of properties used to control the mask behavior.
Property | Type | Description |
---|---|---|
"mask" | []BackgroundElement |
Image or gradient which are used as a view mask |
"mask-clip" | int |
Specifies the painting area for the mask |
"mask-origin" | int |
Specifies the origin area from which the mask will be applied |
Internally, the "mask" property holds an array of BackgroundElement
values, each of which is described in the same way as outlined on the View Background page.
Let's have a look at the example where radial gradient is used to create a view mask.
RUI
GridLayout {
width = 10em,
height = 10em,
padding = 1em,
cell-vertical-align = center,
cell-horizontal-align = center,
content = ImageView {
width = 100%,
height = 100%,
image-horizontal-align = center,
image-vertical-align = center,
src = avatar.jpg,
fit = contain,
// Setting view mask
mask = radial-gradient {
gradient = "#FF000000 0%, #FF000000 40%, #00000000 50%"
},
}
}
Go
view := rui.NewGridLayout(session, rui.Params{
rui.Width: rui.Em(10),
rui.Height: rui.Em(10),
rui.Padding: rui.Em(1),
rui.CellVerticalAlign: rui.CenterAlign,
rui.CellHorizontalAlign: rui.CenterAlign,
rui.Content: rui.NewImageView(session, rui.Params{
rui.Width: rui.Percent(100),
rui.Height: rui.Percent(100),
rui.ImageHorizontalAlign: rui.CenterAlign,
rui.ImageVerticalAlign: rui.CenterAlign,
rui.Source: "avatar.jpg",
rui.Fit: rui.ContainFit,
// Setting view mask
rui.Mask: rui.NewBackgroundRadialGradient(rui.Params{
rui.Gradient: "#FF000000 0%, #FF000000 40%, #00000000 50%",
}),
}),
})
As mentioned earlier view mask can be any type of the gradient or an image, lets see how to define them and what will be the results based on avatar image we've used earlier.
Linear gradient mask.
RUI
GridLayout {
width = 10em,
height = 10em,
padding = 1em,
cell-vertical-align = center,
cell-horizontal-align = center,
content = ImageView {
width = 100%,
height = 100%,
image-horizontal-align = center,
image-vertical-align = center,
src = avatar.jpg,
fit = contain,
// Setting view mask
mask = linear-gradient {
gradient = "#FF000000 0%, #FF000000 70%, #00000000 100%",
},
}
}
Go
view := rui.NewGridLayout(session, rui.Params{
rui.Width: rui.Em(10),
rui.Height: rui.Em(10),
rui.Padding: rui.Em(1),
rui.CellVerticalAlign: rui.CenterAlign,
rui.CellHorizontalAlign: rui.CenterAlign,
rui.Content: rui.NewImageView(session, rui.Params{
rui.Width: rui.Percent(100),
rui.Height: rui.Percent(100),
rui.ImageHorizontalAlign: rui.CenterAlign,
rui.ImageVerticalAlign: rui.CenterAlign,
rui.Source: "avatar.jpg",
rui.Fit: rui.ContainFit,
// Setting view mask
rui.Mask: rui.NewBackgroundLinearGradient(rui.Params{
rui.Gradient: "#FF000000 0%, #FF000000 70%, #00000000 100%",
}),
}),
})
An image used as a mask.
RUI
GridLayout {
width = 10em,
height = 10em,
padding = 1em,
cell-vertical-align = center,
cell-horizontal-align = center,
content = ImageView {
width = 100%,
height = 100%,
image-horizontal-align = center,
image-vertical-align = center,
src = avatar3.jpg,
fit = contain,
// Setting view mask
mask = image {
width = 100%,
height = 100%,
fit = contain,
src = mask.svg,
},
}
}
Go
view := rui.NewGridLayout(session, rui.Params{
rui.Width: rui.Em(10),
rui.Height: rui.Em(10),
rui.Padding: rui.Em(1),
rui.CellVerticalAlign: rui.CenterAlign,
rui.CellHorizontalAlign: rui.CenterAlign,
rui.Content: rui.NewImageView(session, rui.Params{
rui.Width: rui.Percent(100),
rui.Height: rui.Percent(100),
rui.ImageHorizontalAlign: rui.CenterAlign,
rui.ImageVerticalAlign: rui.CenterAlign,
rui.Source: "avatar3.jpg",
rui.Fit: rui.ContainFit,
// Setting view mask
rui.Mask: rui.NewBackgroundImage(rui.Params{
rui.Width: rui.Percent(100),
rui.Height: rui.Percent(100),
rui.Fit: rui.ContainFit,
rui.Source: "mask.svg",
}),
}),
})
To retrieve the values of the "mask" property we can use the rui.GetMask()
global function, which will return an array of the BackgroundElement
values.
Go
masks := rui.GetMask(view, "view-id")
for _, mask := range masks {
rui.DebugLogF("View has a mask of type %s\n", mask.Tag()) // Tag could be "image", "linear-gradient", "radial-gradient", and "conic-gradient"
switch mask.Tag() {
case "image":
// Do something with the value
case "linear-gradient", "radial-gradient", "conic-gradient":
// Do something with the value
}
}
The BackgroundElement
itself also contains properties the values of which can be retrieved using the Get()
method of that interface.
By default, the mask extends to the outer edge of the border, but using the "mask-clip" property, we can restrict this to other areas.
The property can contain one of the following values:
Value | Name | Description |
---|---|---|
BorderBox |
"border-box" | The mask extends to the outer edge of the border(but below the border in z-order) |
PaddingBox |
"padding-box" | The mask extends to the outer edge of the padding |
ContentBox |
"content-box" | The mask is restricted to the content box area |
When using rui.BorderBox
as the mak clip value, the mask will conform to the shape of the view.
To exclude the border of the view from the mask we can use the rui.PaddingBox
value.
Also we can configure the mask to appear only inside the view content area by using the rui.ContentBox
value.
As any other property we can set the "mask-clip" property either during creation of the view(from resource file or code) and at runtime. Lets take a look at a few examples.
Setting mask clip property from code.
Go
if ok := view.Set(rui.MaskClip, rui.ContentBox); ok {
// Success
}
Setting property from the resource file.
RUI
// View hierarchy
...
// Setting view property
mask-clip = content-box,
// The rest of view hierarchy
...
To retrieve the value of the "mask-clip" property we can use the rui.GetMaskClip()
global function, which will return a numeric value of the constant.
Go
maskClip := rui.GetMaskClip(view, "view-id")
// Do something with the value
Besides the mask clipping functionality we can control the origin point of the mask, this is done by utilizing the "mask-origin" property.
The property can contain one of the following values:
Value | Name | Description |
---|---|---|
BorderBox |
"none" | The mask is positioned relative to the border box |
PaddingBox |
"solid" | The mask is positioned relative to the padding box |
ContentBox |
"dashed" | The mask is positioned relative to the content box |
When using the rui.BorderBox
as the mask origin value, the mask will be applied starting from the shape of the view.
To apply the mask starting from the internal border edge we can use the rui.PaddingBox
value.
Depending on the requirements, we may wish to apply the mask starting from the content box.
For this purpose, the rui.ContentBox
value is used.
As any other property we can set the "mask-origin" property either during creation of the view(from resource file or code) and at runtime. Lets take a look at a few examples.
Setting mask origin property from code.
Go
if ok := view.Set(rui.MaskOrigin, rui.PaddingBox); ok {
// Success
}
Setting property from the resource file.
RUI
// View hierarchy
...
// Setting view property
mask-origin = padding-box,
// The rest of view hierarchy
...
To retrieve the value of the "mask-origin" property we can use the rui.GetMaskOrigin()
global function, which will return a numeric value of the constant.
Go
maskOrigin := rui.GetMaskOrigin(view, "view-id")
// Do something with the value