Skip to content

Android Mask not working #2875

@sokolovdm

Description

@sokolovdm

Description

Here is my component that renders this preloader.
Figma screenshots:
Image

It works perfectly on iOS, but the mask doesn't work on Android.
iOS screenshots:

Image

Android screenshots:

Image
import React, { useEffect } from 'react'
import Svg, {
    Circle,
    Defs,
    G,
    Path,
    Mask,
    LinearGradient,
    Stop,
} from 'react-native-svg'
import Animated, {
    Easing,
    useAnimatedStyle,
    useSharedValue,
    withRepeat,
    withTiming,
} from 'react-native-reanimated'
import { LoaderProps } from '@/shared/ui/Loader/model'
import { rem } from '@/lib'

export function Loader({ size = 56, style }: LoaderProps) {
    const outerRadius = rem(size)
    const segments = rem(size) 
    const id = Date.now().toString() 

    const segmentsArray = []
    const gradientsArray = []

    for (let i = 0; i < segments; i++) {
        const startAngle = (i / segments) * 360 - 90
        const endAngle = ((i + 1) / segments) * 360 - 90
        const largeArc = endAngle - startAngle >= 180 ? 1 : 0

        const x1 =
            outerRadius + outerRadius * Math.cos((Math.PI * startAngle) / 180)
        const y1 =
            outerRadius + outerRadius * Math.sin((Math.PI * startAngle) / 180)

        const x2 =
            outerRadius + outerRadius * Math.cos((Math.PI * endAngle) / 180)
        const y2 =
            outerRadius + outerRadius * Math.sin((Math.PI * endAngle) / 180)

        segmentsArray.push(
            <Path
                key={i}
                d={`M ${outerRadius} ${outerRadius} L ${x1} ${y1} A ${outerRadius} ${outerRadius} 0 ${largeArc} 1 ${x2} ${y2} Z`}
                stroke="none"
                fill={`url(#${id}-grad-${i})`}
            />,
        )
        const fromOpacity = i / segments
        const toOpacity = (i + 1) / segments
        gradientsArray.push(
            <LinearGradient
                key={i}
                id={`${id}-grad-${i}`}
                x1="0%"
                y1="0%"
                x2="0%"
                y2="100%">
                <Stop
                    offset="0%"
                    stopColor="black"
                    stopOpacity={fromOpacity}
                />
                <Stop
                    offset="100%"
                    stopColor="black"
                    stopOpacity={toOpacity}
                />
            </LinearGradient>,
        )
    }

    const rotation = useSharedValue(0)

    const animatedStyle = useAnimatedStyle(() => ({
        transform: [{ rotate: `${rotation.value}deg` }],
    }))

    useEffect(() => {
        rotation.value = withRepeat(
            withTiming(360, { duration: 1000, easing: Easing.linear }),
            -1,
            false,
        )
    })

    return (
        <Animated.View
            style={[
                style,
                {
                    width: rem(size),
                    height: rem(size),
                },
                animatedStyle,
            ]}>
            <Svg
                width={rem(size)}
                height={rem(size)}
                viewBox={`0 0 ${rem(size)} ${rem(size)}`}>
                <Defs>
                    {gradientsArray}
                    <Mask id={id}>
                        <Circle
                            cx={rem(size) / 2}
                            cy={rem(size) / 2}
                            r={outerRadius}
                            fill="white"
                        />
                        <Circle
                            cx={rem(size) / 2}
                            cy={rem(size) / 2}
                            r={rem(size) / 2 - rem(size) * 0.9090909}
                            fill="black"
                        />
                    </Mask>
                </Defs>

                <G mask={`url(#${id})`}>{segmentsArray}</G>
            </Svg>
        </Animated.View>
    )
}

Steps to reproduce

  1. Just add in App layout

Snack or a link to a repository

  • Nope

SVG version

15.12.1

React Native version

0.81.5

Platforms

Android, iOS

JavaScript runtime

None

Workflow

Expo Go

Architecture

Fabric (New Architecture)

Build type

Debug app & dev bundle

Device

Android emulator

Device model

Pixel 9 Pro XL

Acknowledgements

Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    Missing reproThis issue need minimum repro scenario

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions