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%",
        }),
    }),
})

Mask example 1

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%",
        }),
    }),
})

Mask example 2

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",
        }),
    }),
})

Mask example 3

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