How to use gradient colors in RN projects
1280103995 opened this issue · comments
I looked at the examples for the web version, but it didn't solve my problem.
I run react-native init myapp
to create a RN project, and run yarn add react-native-svg react-native-countdown-circle-timer@3.0.8
to add dependencies.
This is my App.js
import React from 'react';
import {Text, View} from 'react-native';
import Svg, {Defs, LinearGradient, Stop} from "react-native-svg";
import { CountdownCircleTimer } from 'react-native-countdown-circle-timer'
export default function App() {
return (
<View>
<Svg width="0" height="0" >
<Defs>
<LinearGradient id="your-unique-id" x1="1" y1="0" x2="0" y2="0">
<Stop offset="5%" stopColor="gold"/>
<Stop offset="95%" stopColor="red"/>
</LinearGradient>
</Defs>
</Svg>
<CountdownCircleTimer
colors="url(#your-unique-id)"
size={200}
strokeWidth={20}
duration={60}
initialRemainingTime={25}>
{({remainingTime}) => <Text>{remainingTime}</Text>}
</CountdownCircleTimer>
</View>
);
}
Hey @1280103995, it seems your right. I open an issue with react-native-svg
to clarify that.
Meanwhile I recommend using the hook
and build your own component and gradient. It should look like something like this:
import { useCountdown } from 'react-native-countdown-circle-timer'
const Component = () => {
const {
path,
pathLength,
stroke,
strokeDashoffset,
remainingTime,
elapsedTime,
size,
strokeWidth,
} = useCountdown({ isPlaying: true, duration: 7, colors: '#abc' })
return (
<View style={getWrapperStyle(size) as StyleProp<ViewStyle>}>
<Svg width={size} height={size}>
<Defs>
<LinearGradient id="your-unique-id" x1="1" y1="0" x2="0" y2="0">
<Stop offset="5%" stopColor="gold"/>
<Stop offset="95%" stopColor="red"/>
</LinearGradient>
</Defs>
<Path
d={path}
fill="none"
stroke={trailColor ?? '#d9d9d9'}
strokeWidth={trailStrokeWidth ?? strokeWidth}
/>
{elapsedTime !== duration && (
<Path
d={path}
fill="none"
sroke="url(#your-unique-id)"
strokeLinecap={strokeLinecap ?? 'round'}
strokeWidth={strokeWidth}
strokeDasharray={pathLength}
strokeDashoffset={strokeDashoffset}
/>
)}
</Svg>
{typeof children === 'function' && (
<View style={timeStyle as StyleProp<ViewStyle>}>
{children({ remainingTime, elapsedTime, color: stroke })}
</View>
)}
</View>
)
}
This one is going to work since the gradient and the consumer are under the same SVG element.
I tried using your code, but the gradient still doesn't show.
import React from 'react';
import {Text, View} from 'react-native';
import Svg, {Defs, LinearGradient, Path, Stop} from 'react-native-svg';
import { useCountdown } from 'react-native-countdown-circle-timer'
export default function App() {
const duration = 60;
const {
path,
pathLength,
stroke,
strokeDashoffset,
remainingTime,
elapsedTime,
size,
strokeWidth,
} = useCountdown({ isPlaying: true, duration, colors: '#ffabef', initialRemainingTime: 25 })
return (
<View style={{width: size, height: size}}>
<Svg width={size} height={size}>
<Defs>
<LinearGradient id="your-unique-id" x1="1" y1="0" x2="0" y2="0">
<Stop offset="5%" stopColor="gold"/>
<Stop offset="95%" stopColor="red"/>
</LinearGradient>
</Defs>
<Path
d={path}
fill="none"
stroke={'#d9d9d9'}
strokeWidth={strokeWidth}
/>
{elapsedTime !== duration && (
<Path
d={path}
fill="none"
sroke="url(#your-unique-id)"
strokeLinecap={'butt'}
strokeWidth={strokeWidth}
strokeDasharray={pathLength}
strokeDashoffset={strokeDashoffset}
/>
)}
</Svg>
</View>
);
}
By the way, my network is poor and I often can't open the Github website, so sometimes the reply will be slow.
Shockingly, I copied two files from v2: DefsLinearGradient
and colorsValidator
for the gradient component and it worked just fine.
App.js
import React from 'react';
import {View} from 'react-native';
import Svg, {Path} from 'react-native-svg';
import { useCountdown } from 'react-native-countdown-circle-timer'
import {DefsLinearGradient} from './src/DefsLinearGradient';
export default function App() {
const duration = 60;
const colors = [
['#6E40AA', 0.33],
['#DF40A1', 0.33],
['#FF704E', 0.34],
]
const {
path,
pathLength,
stroke,
strokeDashoffset,
remainingTime,
elapsedTime,
size,
strokeWidth,
} = useCountdown({ isPlaying: true, duration, colors, initialRemainingTime: 59 })
return (
<View style={{width: size, height: size}}>
<Svg width={size} height={size}>
<DefsLinearGradient
colors={colors}
gradientId={'your-unique-id'}
/>
<Path
d={path}
fill="none"
stroke={'#d9d9d9'}
strokeWidth={strokeWidth}
/>
{elapsedTime !== duration && (
<Path
d={path}
fill="none"
stroke="url(#your-unique-id)"
strokeLinecap={'butt'}
strokeWidth={strokeWidth}
strokeDasharray={pathLength}
strokeDashoffset={strokeDashoffset}
/>
)}
</Svg>
</View>
);
}
Hmm, that is very strange. The only difference I see is that the offset
is define in numbers from 0 to 1 and colors are in HEX format. Otherwise it seems the same.
I updated the docs to reflect the new way to build the gradient. I do not think that we gonna have an answer on the issue I opened with react-native-svg
and as we can see it does not work if the gradient detentions is not in the same SVG as the usage of it.
Here is link to the demo on the recommended way to do t he gradient https://snack.expo.dev/@dimitrov/react-native-countdown-circle-timer-gradient?platform=ios
Why we can't use gradient without using hooks?
Also how to restart timer which is based on useCountDown
hook
Why we can't use gradient without using hooks?
Also how to restart timer which is based on
useCountDown
hook
+1
I'd also like to use a gradient and at the same time be able to restart the timer
Hey you can restart the timer the same way you do it with the component, by passing a key
. So below is your CountdownCircleTimer:
// src/components/timer - this is your folder for shared components
export const CountdownCircleTimer = ({ duration, isPlaying, .... }) => {
const {
path,
pathLength,
stroke,
strokeDashoffset,
remainingTime,
elapsedTime,
size,
strokeWidth,
} = useCountdown({ isPlaying: true, duration, colors: 'url(#your-unique-id)' })
return (
<View style={styles.container}>
<View style={{ width: size, height: size, position: 'relative' }}>
<Svg width={size} height={size}>
<Defs>
<LinearGradient id="your-unique-id" x1="1" y1="0" x2="0" y2="0">
<Stop offset="5%" stopColor="gold"/>
<Stop offset="95%" stopColor="red"/>
</LinearGradient>
</Defs>
<Path
d={path}
fill="none"
stroke="#d9d9d9"
strokeWidth={strokeWidth}
/>
{elapsedTime !== duration && (
<Path
d={path}
fill="none"
stroke={stroke}
strokeLinecap="butt"
strokeWidth={strokeWidth}
strokeDasharray={pathLength}
strokeDashoffset={strokeDashoffset}
/>
)}
</Svg>
<View style={styles.time}>
<Text style={{ fontSize: 36 }}>{remainingTime}</Text>
</View>
</View>
</View>
);
}
Then in your App you just use it as it was before
import { CountdownCircleTimer } from 'src/components/timer '
<CountdownCircleTimer key="some-new-key-to-restart" duration={10} isPlaying />
Does it help?
Yeap, it helps. I already figured an answer by myself, but thanks 🙏
Worked for me as well. Thanks!