├── .gitignore ├── App.tsx ├── README.md ├── app.json ├── assets ├── adaptive-icon.png ├── favicon.png ├── icon.png └── splash.png ├── babel.config.js ├── package.json ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import { LinearGradient } from 'expo-linear-gradient'; 2 | import { StatusBar } from 'expo-status-bar'; 3 | import { useEffect, useState } from 'react'; 4 | import { 5 | StyleSheet, 6 | Text, 7 | TouchableOpacity, 8 | View, 9 | } from 'react-native'; 10 | import Animated, { 11 | Easing, 12 | interpolate, 13 | interpolateColor, 14 | runOnJS, 15 | useAnimatedProps, 16 | useSharedValue, 17 | withRepeat, 18 | withSequence, 19 | withSpring, 20 | withTiming, 21 | } from 'react-native-reanimated'; 22 | import { 23 | SafeAreaProvider, 24 | SafeAreaView, 25 | } from 'react-native-safe-area-context'; 26 | 27 | const AnimatedLinearGradient = 28 | Animated.createAnimatedComponent(LinearGradient); 29 | 30 | export default function App() { 31 | const colorsValue1 = useSharedValue(1); 32 | const colorsValue2 = useSharedValue(1); 33 | const colorsValue3 = useSharedValue(1); 34 | 35 | const [androidColors, setAndroidColors] = useState([ 36 | '#7AF5C1', 37 | '#7FEC90', 38 | '#EFFB60', 39 | ]); 40 | 41 | useEffect(() => { 42 | colorsValue1.value = withRepeat( 43 | withSequence( 44 | withTiming(0, { 45 | duration: 3000, 46 | easing: Easing.quad, 47 | }), 48 | withTiming(2, { 49 | duration: 2000, 50 | easing: Easing.quad, 51 | }) 52 | ), 53 | -1, 54 | true 55 | ); 56 | 57 | colorsValue2.value = withRepeat( 58 | withSequence( 59 | withTiming(0, { 60 | duration: 2000, 61 | easing: Easing.quad, 62 | }), 63 | withTiming(2, { 64 | duration: 3000, 65 | easing: Easing.quad, 66 | }) 67 | ), 68 | -1, 69 | true 70 | ); 71 | 72 | colorsValue3.value = withRepeat( 73 | withSequence( 74 | withTiming(0, { 75 | duration: 3000, 76 | easing: Easing.quad, 77 | }), 78 | withTiming(2, { 79 | duration: 2000, 80 | easing: Easing.quad, 81 | }) 82 | ), 83 | -1, 84 | true 85 | ); 86 | }, []); 87 | 88 | const animatedProps = useAnimatedProps(() => { 89 | const colors = [ 90 | interpolateColor( 91 | colorsValue1.value, 92 | [0, 1, 2], 93 | ['#7AF5C1', '#80E987', '#EFFB60'] 94 | ), 95 | interpolateColor( 96 | colorsValue2.value, 97 | [0, 1, 2], 98 | ['#80E987', '#EFFB60', '#7AF5C1'] 99 | ), 100 | interpolateColor( 101 | colorsValue3.value, 102 | [0, 1, 2], 103 | ['#EFFB60', '#7AF5C1', '#80E987'] 104 | ), 105 | ]; 106 | 107 | runOnJS(setAndroidColors)(colors); 108 | 109 | return { 110 | colors, 111 | }; 112 | }); 113 | 114 | return ( 115 | 116 | 117 | 118 | 141 | 149 | 150 | 151 | 152 | 153 | 154 | Welcome to 155 | new era of 156 | banking 157 | 158 | 159 | 160 | 164 | Log in 165 | 166 | 167 | 171 | Register 172 | 173 | 174 | 175 | 176 | 177 | ); 178 | } 179 | 180 | const styles = StyleSheet.create({ 181 | container: { 182 | flex: 1, 183 | backgroundColor: '#fff', 184 | flexDirection: 'column', 185 | paddingHorizontal: 20, 186 | paddingVertical: 20, 187 | }, 188 | gradientContainer: { 189 | flex: 2, 190 | }, 191 | linearGradient: { 192 | flex: 1, 193 | borderRadius: 20, 194 | }, 195 | footerContainer: { 196 | flex: 1, 197 | }, 198 | titleContainer: { 199 | paddingVertical: 28, 200 | }, 201 | title: { 202 | fontSize: 40, 203 | fontWeight: '400', 204 | lineHeight: 42, 205 | }, 206 | buttonsContainer: { 207 | flexDirection: 'column', 208 | rowGap: 10, 209 | }, 210 | button: { 211 | paddingVertical: 10, 212 | paddingHorizontal: 20, 213 | borderRadius: 5, 214 | backgroundColor: '#000', 215 | borderColor: '#000', 216 | borderWidth: 2, 217 | justifyContent: 'center', 218 | alignItems: 'center', 219 | }, 220 | buttonText: { 221 | color: '#fff', 222 | fontSize: 18, 223 | fontWeight: '600', 224 | }, 225 | secondaryButton: { 226 | paddingVertical: 10, 227 | paddingHorizontal: 20, 228 | borderRadius: 5, 229 | backgroundColor: '#fff', 230 | borderColor: '#000', 231 | borderWidth: 2, 232 | justifyContent: 'center', 233 | alignItems: 'center', 234 | }, 235 | secondaryButtonText: { 236 | color: '#000', 237 | fontSize: 18, 238 | fontWeight: '600', 239 | }, 240 | }); 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ❇️ Linear gradient animation with Expo app 2 | --- 3 | 4 | ### 🚀 How to use 5 | - Install packages with `yarn`. 6 | - Run `yarn start` to start the bundler. 7 | 8 | iOS | Android 9 | ------------- | ------------- 10 | ![ezgif com-optimize](https://github.com/pzatorski/expo-linear-gradient-animation/assets/11720377/cb929aa0-dd95-442a-9563-fbf926d5e400) | ![ezgif com-video-to-gif-converter](https://github.com/pzatorski/expo-linear-gradient-animation/assets/11720377/08ba3434-228a-4de0-8626-827fb692a90a) 11 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "linear-gradient-animation", 4 | "slug": "linear-gradient-animation", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "assetBundlePatterns": [ 15 | "**/*" 16 | ], 17 | "ios": { 18 | "supportsTablet": true 19 | }, 20 | "android": { 21 | "adaptiveIcon": { 22 | "foregroundImage": "./assets/adaptive-icon.png", 23 | "backgroundColor": "#ffffff" 24 | } 25 | }, 26 | "web": { 27 | "favicon": "./assets/favicon.png" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pzatorski/expo-linear-gradient-animation/42f50f6834f13b6fb05da2eaaaa4fd272ef64de6/assets/adaptive-icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pzatorski/expo-linear-gradient-animation/42f50f6834f13b6fb05da2eaaaa4fd272ef64de6/assets/favicon.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pzatorski/expo-linear-gradient-animation/42f50f6834f13b6fb05da2eaaaa4fd272ef64de6/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pzatorski/expo-linear-gradient-animation/42f50f6834f13b6fb05da2eaaaa4fd272ef64de6/assets/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | plugins: ['react-native-reanimated/plugin'], 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linear-gradient-animation", 3 | "version": "1.0.0", 4 | "main": "node_modules/expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo start --android", 8 | "ios": "expo start --ios", 9 | "web": "expo start --web" 10 | }, 11 | "dependencies": { 12 | "expo": "~49.0.8", 13 | "expo-linear-gradient": "~12.3.0", 14 | "expo-status-bar": "~1.6.0", 15 | "react": "18.2.0", 16 | "react-native": "0.72.4", 17 | "react-native-reanimated": "~3.3.0", 18 | "react-native-safe-area-context": "4.6.3" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.20.0", 22 | "@types/react": "~18.2.14", 23 | "typescript": "^5.1.3" 24 | }, 25 | "private": true 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true 5 | } 6 | } 7 | --------------------------------------------------------------------------------