├── .gitignore ├── README.md ├── app.json ├── app ├── _layout.tsx ├── city.tsx └── index.tsx ├── assets └── images │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ ├── partial-react-logo.png │ ├── react-logo.png │ ├── react-logo@2x.png │ ├── react-logo@3x.png │ └── splash.png ├── babel.config.js ├── components └── CityDetails.tsx ├── package.json └── tsconfig.json /.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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your Expo app 👋 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 | ## Get started 6 | 7 | 1. Install dependencies 8 | 9 | ```bash 10 | npm install 11 | ``` 12 | 13 | 2. Start the app 14 | 15 | ```bash 16 | npx expo start 17 | ``` 18 | 19 | In the output, you'll find options to open the app in a 20 | 21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/) 22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) 23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) 24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo 25 | 26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction). 27 | 28 | ## Get a fresh project 29 | 30 | When you're ready, run: 31 | 32 | ```bash 33 | npm run reset-project 34 | ``` 35 | 36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing. 37 | 38 | ## Learn more 39 | 40 | To learn more about developing your project with Expo, look at the following resources: 41 | 42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). 43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. 44 | 45 | ## Join the community 46 | 47 | Join our community of developers creating universal apps. 48 | 49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. 50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions. 51 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "expo-scroll-anim", 4 | "slug": "expo-scroll-anim", 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 | -------------------------------------------------------------------------------- /app/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DarkTheme, 3 | DefaultTheme, 4 | ThemeProvider, 5 | } from "@react-navigation/native"; 6 | import { useColorScheme } from "react-native"; 7 | import { Stack } from "expo-router"; 8 | import "react-native-reanimated"; 9 | 10 | declare module "@react-navigation/native" { 11 | export type ExtendedTheme = { 12 | dark: boolean; 13 | colors: { 14 | primary: string; 15 | background: string; 16 | card: string; 17 | text: string; 18 | border: string; 19 | notification: string; 20 | subtitle: string; 21 | paragraph: string; 22 | overlay: string; 23 | }; 24 | }; 25 | export function useTheme(): ExtendedTheme; 26 | } 27 | 28 | const dark = { 29 | ...DarkTheme, 30 | colors: { 31 | ...DarkTheme.colors, 32 | subtitle: "#EEEEEE", 33 | paragraph: "#DDDDDD", 34 | overlay: "rgba(0,0,0,0.4)", 35 | }, 36 | }; 37 | 38 | const light = { 39 | ...DefaultTheme, 40 | colors: { 41 | ...DefaultTheme.colors, 42 | subtitle: "#333333", 43 | paragraph: "#222222", 44 | overlay: "rgba(255,255,255,0.1)", 45 | }, 46 | }; 47 | 48 | export default function RootLayout() { 49 | const colorScheme = useColorScheme(); 50 | return ( 51 | 52 | 60 | 61 | 67 | 68 | 69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /app/city.tsx: -------------------------------------------------------------------------------- 1 | import { Dimensions, StyleSheet, Text, View } from "react-native"; 2 | import React from "react"; 3 | import { Image } from "expo-image"; 4 | import { useTheme } from "@react-navigation/native"; 5 | import Animated, { 6 | Extrapolation, 7 | interpolate, 8 | interpolateColor, 9 | useAnimatedRef, 10 | useAnimatedScrollHandler, 11 | useAnimatedStyle, 12 | useSharedValue, 13 | } from "react-native-reanimated"; 14 | import { useSafeAreaInsets } from "react-native-safe-area-context"; 15 | import { BlurView } from "expo-blur"; 16 | import { useHeaderHeight } from "@react-navigation/elements"; 17 | import CityDetails from "@/components/CityDetails"; 18 | 19 | const IMAGE_URI = 20 | "https://wallpapers.com/images/hd/jal-mahal-water-palace-jaipur-nighttime-uhki0tnbfn2lgovf.jpg"; 21 | const BANNER_HEIGHT = Dimensions.get("window").width; 22 | const IMAGE_HEIGHT = 50; 23 | const EXTRA_PADDING = 20; 24 | 25 | const City = () => { 26 | const theme = useTheme(); 27 | const { top, bottom } = useSafeAreaInsets(); 28 | const scrollRef = useAnimatedRef(); 29 | const scrollOffset = useSharedValue(0); 30 | 31 | const HEADER_HEIGHT = useHeaderHeight(); 32 | 33 | const UPPER_BOUND = [0, BANNER_HEIGHT / 2]; 34 | 35 | const scrollHandler = useAnimatedScrollHandler({ 36 | onScroll: (event) => { 37 | scrollOffset.value = event.contentOffset.y; 38 | }, 39 | }); 40 | 41 | const animatedHeaderStyle = useAnimatedStyle(() => { 42 | const height = interpolate( 43 | scrollOffset.value, 44 | [0, BANNER_HEIGHT / 2 + EXTRA_PADDING], 45 | [BANNER_HEIGHT, HEADER_HEIGHT + 10], 46 | Extrapolation.CLAMP 47 | ); 48 | const translateY = interpolate( 49 | scrollOffset.value, 50 | [-BANNER_HEIGHT, 0, BANNER_HEIGHT], 51 | [-BANNER_HEIGHT * 0.5, 0, 0], 52 | Extrapolation.CLAMP 53 | ); 54 | 55 | const scale = interpolate( 56 | scrollOffset.value, 57 | [-BANNER_HEIGHT, 0, BANNER_HEIGHT], 58 | [2, 1, 1], 59 | Extrapolation.CLAMP 60 | ); 61 | 62 | return { 63 | height: height, 64 | transform: [{ translateY: translateY }, { scale: scale }], 65 | }; 66 | }); 67 | 68 | const animatedTitleStyle = useAnimatedStyle(() => { 69 | const scale = interpolate( 70 | scrollOffset.value, 71 | [-BANNER_HEIGHT / 2, 0, BANNER_HEIGHT / 2], 72 | [1.3, 1, 0.8], 73 | Extrapolation.CLAMP 74 | ); 75 | 76 | const translateY = interpolate( 77 | scrollOffset.value, 78 | UPPER_BOUND, 79 | [ 80 | BANNER_HEIGHT - 80, 81 | top + ((HEADER_HEIGHT - top) / 2 - IMAGE_HEIGHT / 1.8), 82 | ], 83 | Extrapolation.CLAMP 84 | ); 85 | 86 | const translateX = interpolate( 87 | scrollOffset.value, 88 | [-BANNER_HEIGHT / 2, 0, BANNER_HEIGHT / 2], 89 | [scale * 2 * EXTRA_PADDING, EXTRA_PADDING, 2 * IMAGE_HEIGHT], 90 | Extrapolation.CLAMP 91 | ); 92 | 93 | return { 94 | transform: [ 95 | { 96 | translateX, 97 | }, 98 | { 99 | translateY, 100 | }, 101 | { 102 | scale, 103 | }, 104 | ], 105 | }; 106 | }); 107 | 108 | const animatedImageStyle = useAnimatedStyle(() => { 109 | const width = interpolate( 110 | scrollOffset.value, 111 | UPPER_BOUND, 112 | [BANNER_HEIGHT, IMAGE_HEIGHT], 113 | Extrapolation.CLAMP 114 | ); 115 | 116 | const translateY = interpolate( 117 | scrollOffset.value, 118 | UPPER_BOUND, 119 | [0, top + ((HEADER_HEIGHT - top) / 2 - IMAGE_HEIGHT / 1.8)], 120 | Extrapolation.CLAMP 121 | ); 122 | 123 | const translateX = interpolate( 124 | scrollOffset.value, 125 | UPPER_BOUND, 126 | [0, IMAGE_HEIGHT], 127 | Extrapolation.CLAMP 128 | ); 129 | 130 | const borderRadius = interpolate( 131 | scrollOffset.value, 132 | UPPER_BOUND, 133 | [0, width], 134 | Extrapolation.CLAMP 135 | ); 136 | 137 | return { 138 | borderRadius: borderRadius, 139 | aspectRatio: 1, 140 | maxHeight: width, 141 | transform: [ 142 | { 143 | translateY, 144 | }, 145 | { 146 | translateX, 147 | }, 148 | ], 149 | }; 150 | }); 151 | 152 | const animatedOverlay = useAnimatedStyle(() => { 153 | const backgroundColor = interpolateColor(scrollOffset.value, UPPER_BOUND, [ 154 | theme.colors.overlay, 155 | "rgba(0,0,0,0)", 156 | ]); 157 | return { 158 | backgroundColor, 159 | }; 160 | }); 161 | 162 | const animatedPaddingSupport = useAnimatedStyle(() => { 163 | const height = interpolate( 164 | scrollOffset.value, 165 | [0, BANNER_HEIGHT - HEADER_HEIGHT - 100], 166 | [0, BANNER_HEIGHT - HEADER_HEIGHT - 100], 167 | Extrapolation.CLAMP 168 | ); 169 | return { 170 | height: height, 171 | }; 172 | }); 173 | 174 | const ListTitle = () => { 175 | return ( 176 | 177 | 178 | Jaipur 179 | 180 | 181 | The Pink Jewel of India 182 | 183 | 184 | ); 185 | }; 186 | 187 | const ListHeaderComponent = () => { 188 | return ( 189 | <> 190 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | ); 204 | }; 205 | return ( 206 | 207 | 217 | 218 | 219 | 220 | 221 | ); 222 | }; 223 | 224 | export default City; 225 | 226 | const styles = StyleSheet.create({ 227 | flexOne: { 228 | flex: 1, 229 | }, 230 | contentContainerStyle: { 231 | gap: 25, 232 | }, 233 | listTitleContainer: { 234 | position: "absolute", 235 | gap: 2, 236 | }, 237 | titleStyle: { 238 | fontSize: 25, 239 | fontWeight: "500", 240 | }, 241 | subTitleStyle: { 242 | fontSize: 15, 243 | fontWeight: "400", 244 | }, 245 | headerStyle: { 246 | height: BANNER_HEIGHT, 247 | width: "100%", 248 | }, 249 | bannerStyle: { 250 | flex: 1, 251 | overflow: "hidden", 252 | }, 253 | }); 254 | -------------------------------------------------------------------------------- /app/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Pressable, StyleSheet, Text, View } from "react-native"; 3 | import { useTheme } from "@react-navigation/native"; 4 | import { useRouter } from "expo-router"; 5 | 6 | const Main = () => { 7 | const router = useRouter(); 8 | const theme = useTheme(); 9 | return ( 10 | 11 | router.navigate("/city")}> 12 | Main 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default Main; 19 | 20 | const styles = StyleSheet.create({ 21 | container: { 22 | flex: 1, 23 | justifyContent: "center", 24 | alignItems: "center", 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /assets/images/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/adaptive-icon.png -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/partial-react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/partial-react-logo.png -------------------------------------------------------------------------------- /assets/images/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/react-logo.png -------------------------------------------------------------------------------- /assets/images/react-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/react-logo@2x.png -------------------------------------------------------------------------------- /assets/images/react-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/react-logo@3x.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunabhverma/expo-animated-scroll-header/3df6890243b3f31872bfc94966c2032eab28f3c1/assets/images/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /components/CityDetails.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View } from "react-native"; 3 | import { useTheme } from "@react-navigation/native"; 4 | 5 | export default function CityDetails() { 6 | const theme = useTheme(); 7 | return ( 8 | 9 | 10 | Jaipur is famously known as the Pink City due to the uniform terracotta 11 | pink hue of its buildings, a color that symbolizes hospitality. This 12 | tradition dates back to 1876 when the city was painted pink to welcome 13 | the Prince of Wales, later King Edward VII. The old part of the city 14 | still retains this pink charm, especially around the Johari Bazaar and 15 | Bapu Bazaar areas. 16 | 17 | 18 | 19 | The striking Hawa Mahal (Palace of Winds) is one of Jaipur’s most famous 20 | landmarks. Built in 1799, it was designed for royal women to observe 21 | street festivals and processions without being seen. Its façade, with 22 | 953 small windows or 'jharokhas', is an architectural masterpiece. 23 | 24 | 25 | 26 | History of Jaipur 27 | 28 | 29 | Jaipur's origins can be traced back to the reign of Maharaja Sawai Jai 30 | Singh II, who moved the capital from Amber Fort to Jaipur to accommodate 31 | the growing population and ensure better defense. The city was 32 | meticulously planned by architect Vidyadhar Bhattacharya based on the 33 | principles of Vastu Shastra, making it one of India’s first planned 34 | cities. 35 | 36 | 37 | 38 | The foundation of Jaipur in the 18th century marked the beginning of a 39 | new era for the Rajputs, as the city grew to become a center of arts, 40 | science, and culture. 41 | 42 | 43 | 44 | Jaipur's Royal Heritage 45 | 46 | 47 | Jaipur’s royalty continues to be a significant part of the city's 48 | identity. The City Palace is a royal residence that stands as a 49 | testament to Jaipur’s regal legacy. Parts of it have been converted into 50 | a museum, showcasing artifacts from the city’s illustrious past, 51 | including weapons, garments, and manuscripts. 52 | 53 | 54 | 55 | Another jewel of the Pink City is the Amber Fort, a short drive from 56 | Jaipur. This stunning hilltop fort was the capital before Jaipur and 57 | boasts a blend of Hindu and Mughal architecture. The fort's Sheesh Mahal 58 | (Hall of Mirrors) is one of its most captivating features. 59 | 60 | 61 | 62 | Jaipur's Festivals and Culture 63 | 64 | 65 | Jaipur is also a cultural hub, hosting a variety of festivals throughout 66 | the year that reflect the city's rich heritage. The Jaipur Literature 67 | Festival, held annually, is the world's largest free literary festival, 68 | attracting renowned authors from across the globe. 69 | 70 | 71 | 72 | The Teej and Gangaur festivals are celebrated with great enthusiasm in 73 | Jaipur. Teej is a monsoon festival that celebrates the union of Goddess 74 | Parvati and Lord Shiva, while Gangaur is dedicated to Goddess Gauri and 75 | Lord Shiva. These festivals feature processions, traditional dance, and 76 | music, adding to the city's vibrant cultural fabric. 77 | 78 | 79 | 80 | Jaipur's Cuisine 81 | 82 | 83 | No trip to Jaipur is complete without indulging in its rich and 84 | flavorful cuisine. Rajasthani dishes like Dal Baati Churma, Gatte Ki 85 | Sabzi, and Laal Maas are must-tries. The city's sweet treats, such as 86 | Ghewar, are especially popular during the festive season. 87 | 88 | 89 | 90 | Visitors can enjoy traditional Rajasthani thalis at local restaurants or 91 | experience fine dining at heritage hotels that offer authentic 92 | Rajasthani flavors combined with modern presentations. 93 | 94 | 95 | 96 | Modern Jaipur 97 | 98 | 99 | In addition to its historic landmarks, Jaipur is rapidly modernizing, 100 | with new developments in infrastructure, shopping malls, and luxury 101 | hotels. Yet, the city strikes a balance between preserving its royal 102 | past and embracing the future. 103 | 104 | 105 | 106 | From its bustling markets filled with traditional handicrafts, textiles, 107 | and gemstones to its luxurious palaces and forts, Jaipur offers an 108 | unforgettable blend of history, culture, and modernity. 109 | 110 | 111 | ); 112 | } 113 | 114 | const styles = StyleSheet.create({ 115 | container: { 116 | marginHorizontal: 16, 117 | }, 118 | subtitle: { 119 | fontSize: 20, 120 | fontWeight: "bold", 121 | marginTop: 16, 122 | marginBottom: 8, 123 | }, 124 | paragraph: { 125 | fontSize: 16, 126 | lineHeight: 24, 127 | marginBottom: 16, 128 | }, 129 | }); 130 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "expo-scroll-anim", 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.2", 19 | "@react-navigation/elements": "^1.3.31", 20 | "@react-navigation/native": "^6.0.2", 21 | "expo": "~51.0.28", 22 | "expo-blur": "~13.0.2", 23 | "expo-constants": "~16.0.2", 24 | "expo-font": "~12.0.9", 25 | "expo-image": "~1.13.0", 26 | "expo-linking": "~6.3.1", 27 | "expo-router": "~3.5.23", 28 | "expo-splash-screen": "~0.27.5", 29 | "expo-status-bar": "~1.12.1", 30 | "expo-system-ui": "~3.0.7", 31 | "expo-web-browser": "~13.0.3", 32 | "react": "18.2.0", 33 | "react-dom": "18.2.0", 34 | "react-native": "0.74.5", 35 | "react-native-gesture-handler": "~2.16.1", 36 | "react-native-reanimated": "~3.10.1", 37 | "react-native-safe-area-context": "4.10.5", 38 | "react-native-screens": "3.31.1", 39 | "react-native-web": "~0.19.10" 40 | }, 41 | "devDependencies": { 42 | "@babel/core": "^7.20.0", 43 | "@types/jest": "^29.5.12", 44 | "@types/react": "~18.2.45", 45 | "@types/react-test-renderer": "^18.0.7", 46 | "jest": "^29.2.1", 47 | "jest-expo": "~51.0.3", 48 | "react-test-renderer": "18.2.0", 49 | "typescript": "~5.3.3" 50 | }, 51 | "private": true 52 | } 53 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------