├── assets ├── images │ ├── icon.png │ ├── favicon.png │ ├── splash.png │ ├── react-logo.png │ ├── adaptive-icon.png │ ├── react-logo@2x.png │ ├── react-logo@3x.png │ └── partial-react-logo.png └── fonts │ └── SpaceMono-Regular.ttf ├── babel.config.js ├── .idea ├── .gitignore ├── vcs.xml ├── modules.xml ├── material_theme_project_new.xml ├── gradient-blur.iml └── git_toolbox_prj.xml ├── app ├── _layout.tsx └── index.tsx ├── tsconfig.json ├── .gitignore ├── app.json ├── README.md ├── package.json └── scripts └── reset-project.js /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/react-logo.png -------------------------------------------------------------------------------- /assets/images/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/adaptive-icon.png -------------------------------------------------------------------------------- /assets/images/react-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/react-logo@2x.png -------------------------------------------------------------------------------- /assets/images/react-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/react-logo@3x.png -------------------------------------------------------------------------------- /assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /assets/images/partial-react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bricezele/React-Native-Gradient-Blur/HEAD/assets/images/partial-react-logo.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # CodeStream ignored files 7 | /codestream.xml 8 | -------------------------------------------------------------------------------- /app/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from "expo-router"; 2 | import Index from "@/app/index"; 3 | 4 | export default function RootLayout() { 5 | return ( 6 | 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true, 5 | "paths": { 6 | "@/*": [ 7 | "./*" 8 | ] 9 | } 10 | }, 11 | "include": [ 12 | "**/*.ts", 13 | "**/*.tsx", 14 | ".expo/types/**/*.ts", 15 | "expo-env.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | dist/ 4 | npm-debug.* 5 | *.jks 6 | *.p8 7 | *.p12 8 | *.key 9 | *.mobileprovision 10 | *.orig.* 11 | web-build/ 12 | 13 | # macOS 14 | .DS_Store 15 | 16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb 17 | # The following patterns were generated by expo-cli 18 | 19 | expo-env.d.ts 20 | # @end expo-cli -------------------------------------------------------------------------------- /.idea/material_theme_project_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/gradient-blur.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/git_toolbox_prj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "gradient-blur", 4 | "slug": "gradient-blur", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/images/icon.png", 8 | "scheme": "myapp", 9 | "userInterfaceStyle": "automatic", 10 | "splash": { 11 | "image": "./assets/images/splash.png", 12 | "resizeMode": "contain", 13 | "backgroundColor": "#ffffff" 14 | }, 15 | "ios": { 16 | "supportsTablet": true 17 | }, 18 | "android": { 19 | "adaptiveIcon": { 20 | "foregroundImage": "./assets/images/adaptive-icon.png", 21 | "backgroundColor": "#ffffff" 22 | } 23 | }, 24 | "web": { 25 | "bundler": "metro", 26 | "output": "static", 27 | "favicon": "./assets/images/favicon.png" 28 | }, 29 | "plugins": [ 30 | "expo-router" 31 | ], 32 | "experiments": { 33 | "typedRoutes": true 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Gradient Blur 👋 2 | 3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app). 4 | 5 | # Gradient Blur Project 6 | 7 | This project demonstrates how to create a gradient blur effect using React Native and several libraries, including `@react-native-masked-view/masked-view`, `expo-linear-gradient`, `react-native-easing-gradient`, and `expo-blur`. 8 | 9 | ## Prerequisites 10 | 11 | Before you start, make sure you have the necessary libraries installed. You can install them using the following commands: 12 | 13 | ```sh 14 | npx expo install @react-native-masked-view/masked-view expo-linear-gradient expo-blur react-native-easing-gradient 15 | ``` 16 | 17 | ## Demo 18 | 19 | https://github.com/bricezele/React-Native-Gradient-Blur/assets/14944418/52337a7b-1d78-44e4-9c55-12b1f0bf7516 20 | 21 | 22 | ## Join me 23 | 24 | - [Twitter](https://x.com/BriceZele) 25 | - [Linkedin](https://www.linkedin.com/in/brice-zele/): Chat with Expo users and ask questions. 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gradient-blur", 3 | "main": "expo-router/entry", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "start": "expo start", 7 | "reset-project": "node ./scripts/reset-project.js", 8 | "android": "expo start --android", 9 | "ios": "expo start --ios", 10 | "web": "expo start --web", 11 | "test": "jest --watchAll", 12 | "lint": "expo lint" 13 | }, 14 | "jest": { 15 | "preset": "jest-expo" 16 | }, 17 | "dependencies": { 18 | "@expo/vector-icons": "^14.0.0", 19 | "@react-navigation/native": "^6.0.2", 20 | "expo": "~51.0.14", 21 | "expo-blur": "~13.0.2", 22 | "expo-constants": "~16.0.2", 23 | "expo-font": "~12.0.7", 24 | "expo-linear-gradient": "~13.0.2", 25 | "expo-linking": "~6.3.1", 26 | "expo-router": "~3.5.16", 27 | "expo-splash-screen": "~0.27.5", 28 | "expo-status-bar": "~1.12.1", 29 | "expo-system-ui": "~3.0.6", 30 | "expo-web-browser": "~13.0.3", 31 | "react": "18.2.0", 32 | "react-dom": "18.2.0", 33 | "react-native": "0.74.2", 34 | "react-native-easing-gradient": "^1.1.1", 35 | "react-native-gesture-handler": "~2.16.1", 36 | "react-native-reanimated": "~3.10.1", 37 | "react-native-safe-area-context": "4.10.1", 38 | "react-native-screens": "3.31.1", 39 | "react-native-web": "~0.19.10", 40 | "@react-native-masked-view/masked-view": "0.3.1" 41 | }, 42 | "devDependencies": { 43 | "@babel/core": "^7.20.0", 44 | "@types/jest": "^29.5.12", 45 | "@types/react": "~18.2.45", 46 | "@types/react-test-renderer": "^18.0.7", 47 | "jest": "^29.2.1", 48 | "jest-expo": "~51.0.1", 49 | "react-test-renderer": "18.2.0", 50 | "typescript": "~5.3.3" 51 | }, 52 | "private": true 53 | } 54 | -------------------------------------------------------------------------------- /scripts/reset-project.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * This script is used to reset the project to a blank state. 5 | * It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file. 6 | * You can remove the `reset-project` script from package.json and safely delete this file after running it. 7 | */ 8 | 9 | const fs = require('fs'); 10 | const path = require('path'); 11 | 12 | const root = process.cwd(); 13 | const oldDirPath = path.join(root, 'app'); 14 | const newDirPath = path.join(root, 'app-example'); 15 | const newAppDirPath = path.join(root, 'app'); 16 | 17 | const indexContent = `import { Text, View } from "react-native"; 18 | 19 | export default function Index() { 20 | return ( 21 | 28 | Edit app/index.tsx to edit this screen. 29 | 30 | ); 31 | } 32 | `; 33 | 34 | const layoutContent = `import { Stack } from "expo-router"; 35 | 36 | export default function RootLayout() { 37 | return ( 38 | 39 | 40 | 41 | ); 42 | } 43 | `; 44 | 45 | fs.rename(oldDirPath, newDirPath, (error) => { 46 | if (error) { 47 | return console.error(`Error renaming directory: ${error}`); 48 | } 49 | console.log('/app moved to /app-example.'); 50 | 51 | fs.mkdir(newAppDirPath, { recursive: true }, (error) => { 52 | if (error) { 53 | return console.error(`Error creating new app directory: ${error}`); 54 | } 55 | console.log('New /app directory created.'); 56 | 57 | const indexPath = path.join(newAppDirPath, 'index.tsx'); 58 | fs.writeFile(indexPath, indexContent, (error) => { 59 | if (error) { 60 | return console.error(`Error creating index.tsx: ${error}`); 61 | } 62 | console.log('app/index.tsx created.'); 63 | 64 | const layoutPath = path.join(newAppDirPath, '_layout.tsx'); 65 | fs.writeFile(layoutPath, layoutContent, (error) => { 66 | if (error) { 67 | return console.error(`Error creating _layout.tsx: ${error}`); 68 | } 69 | console.log('app/_layout.tsx created.'); 70 | }); 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /app/index.tsx: -------------------------------------------------------------------------------- 1 | import {Image, Platform, StyleSheet, Text, useWindowDimensions, View} from "react-native"; 2 | import {easeGradient} from "react-native-easing-gradient"; 3 | import MaskedView from "@react-native-masked-view/masked-view"; 4 | import {LinearGradient} from "expo-linear-gradient"; 5 | import {BlurView} from "expo-blur"; 6 | import Animated, { 7 | interpolate, 8 | useAnimatedScrollHandler, 9 | useAnimatedStyle, 10 | useSharedValue 11 | } from "react-native-reanimated"; 12 | 13 | export default function Index() { 14 | const {width, height} = useWindowDimensions() 15 | // PARALLAX SCROLL 16 | const scrollY = useSharedValue(0) 17 | const onScroll = useAnimatedScrollHandler({ 18 | onScroll: ({ contentOffset: { y } }) => { 19 | scrollY.value = -y; 20 | }, 21 | }) 22 | const imageContainerStyle = useAnimatedStyle(() => ({ 23 | transform: [{scale: interpolate(scrollY.value, [0, height], [1, 2])}] 24 | })) 25 | // LINEAR GRADIENT 26 | const { colors, locations } = easeGradient({ 27 | colorStops: {0: {color: 'transparent'},0.5: {color: 'rgba(0,0,0,0.99)'}, 1: {color: 'black'}}, 28 | }) 29 | return ( 30 | 33 | 36 | 37 | 40 | 41 | 43 | 50 | } 51 | style={[StyleSheet.absoluteFill]}> 52 | 55 | 56 | 57 | Hello World 58 | 59 | 60 | 61 | ); 62 | } 63 | 64 | const styles = StyleSheet.create({ 65 | container: { 66 | flex: 1 67 | }, 68 | blurContainer: { 69 | position: 'absolute', 70 | bottom: 0, 71 | zIndex: 2, 72 | }, 73 | linearGradient: { 74 | bottom: 0, 75 | position: 'absolute', 76 | }, 77 | textContainer: { 78 | alignItems: 'center', 79 | justifyContent: 'center', 80 | flex: 1 81 | }, 82 | text: { 83 | color: 'white', 84 | fontSize: 40, 85 | fontWeight: 'bold' 86 | } 87 | }) 88 | --------------------------------------------------------------------------------