# [react native] sticky header {%youtube hQQZjiW5thk %} ```jsx import React from "react"; import { Text, View, Dimensions, SafeAreaView, StatusBar } from "react-native"; import Animated, { Extrapolate, interpolate } from "react-native-reanimated"; const HeaderImage = ({ y }) => { // 因為 要解決 zIndex 的問題,所以設定 Header 為 absolute // then Header 高度為 50 所以設定開始位置為 50 const top = Animated.interpolate(y, { inputRange: [0, 50], // 線性速度 outputRange: [50, 0], // 位置開始,結束 extrapolate: Extrapolate.CLAMP, useNativeDriver: true, }); // 也可以三個 // const top = y.interpolate({ // inputRange: [0, 40, 100], // 線性速度 // outputRange: [40, 30, 0], // 位置開始,結束 // extrapolate: "clamp", // useNativeDriver: true, // }); return ( <Animated.Image source={{ uri: "https://source.unsplash.com/user/erondu/1600x900" }} style={[ { width: Dimensions.get("screen").width, height: (900 / 1600) * Dimensions.get("screen").width, }, { transform: [{ translateY: top }], }, ]} /> ); }; const App = () => { const scrollY = new Animated.Value(0); const listViewTop = scrollY.interpolate({ inputRange: [0, 250], outputRange: [60, 0], extrapolate: "clamp", useNativeDriver: true, }); return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView style={{ flex: 1 }}> <View style={{ width: Dimensions.get("screen").width }}> <View style={{ position: "absolute", top: 0, left: 0, height: 50, zIndex: 0, width: Dimensions.get("screen").width, backgroundColor: "dodgerblue", justifyContent: "center", paddingLeft: 20, }} > <Text>HEADER</Text> </View> <HeaderImage y={scrollY} /> <Animated.ScrollView // overScrollMode={"never"} scrollEventThrottle={16} onScroll={Animated.event([ { nativeEvent: { contentOffset: { y: scrollY } }, }, ])} style={{ zIndex: 10 }} > <Animated.View style={{ paddingHorizontal: 20, height: 2000, transform: [ { translateY: listViewTop, }, ], }} > <View style={{ marginBottom: 30 }}> <Text style={{ fontSize: 20, fontWeight: "bold" }}>標題一</Text> <Text> Incididunt amet aliqua pariatur quis cupidatat fugiat. Ea quis est cillum id ex laboris eu ea adipisicing. Nulla ex officia nisi adipisicing commodo. Elit sint eiusmod ut non elit irure sint est nulla deserunt tempor. </Text> </View> <View style={{ marginBottom: 30 }}> <Text style={{ fontSize: 20, fontWeight: "bold" }}>標題二</Text> <Text> Incididunt amet aliqua pariatur quis cupidatat fugiat. Ea quis est cillum id ex laboris eu ea adipisicing. Nulla ex officia nisi adipisicing commodo. Elit sint eiusmod ut non elit irure sint est nulla deserunt tempor. </Text> </View> <View style={{ marginBottom: 30 }}> <Text style={{ fontSize: 20, fontWeight: "bold" }}>標題三</Text> <Text> Incididunt amet aliqua pariatur quis cupidatat fugiat. Ea quis est cillum id ex laboris eu ea adipisicing. Nulla ex officia nisi adipisicing commodo. Elit sint eiusmod ut non elit irure sint est nulla deserunt tempor. </Text> </View> <View style={{ marginBottom: 30 }}> <Text style={{ fontSize: 20, fontWeight: "bold" }}>標題四</Text> <Text> Incididunt amet aliqua pariatur quis cupidatat fugiat. Ea quis est cillum id ex laboris eu ea adipisicing. Nulla ex officia nisi adipisicing commodo. Elit sint eiusmod ut non elit irure sint est nulla deserunt tempor. </Text> </View> </Animated.View> </Animated.ScrollView> </View> </SafeAreaView> </> ); }; export default App; ``` ### 參考的網站與文章 - https://medium.com/hackernoon/react-native-animated-header-using-animated-and-scrollview-9749255c149a - https://www.youtube.com/watch?v=xutPT1oZL2M&t=717s