7

I've a short question: How can I apply a different style to a sticky header in a scrollview when it sticks?
I wanna add some shadow/elevation when it sticks.

Thank you :)

Environment

  • react-native: 0.45.0
Daniel Lang
  • 183
  • 2
  • 8

2 Answers2

5

Currently React Native ScrollView component has a property called stickyHeaderIndices, even in your 0.45 version. You can use it to pass your header child index that should be sticky. After that you can use onScroll event to get current scroll position and when achieve your header size add a custom style with shadow. See for the example here:

https://snack.expo.io/@fabiodamasceno/scroll-sticky-styled

or if you prefer:

import * as React from 'react';
import { Text, View, ScrollView } from 'react-native';

const HEADER_HEIGHT = 20;
const headerStyle = {
  backgroundColor: '#e5e5e5',
  height: HEADER_HEIGHT
}
const myShadowStyle = {
  elevation: 3,
  shadowOpacity: 0.2,
  shadowRadius: 6,
  shadowOffset: {
    height: 3,
    width: 0,
  },
};

export default class App extends React.Component {
  state = {
     headerStyle : {
     ...headerStyle
    }
  }
  render() {
    return (
     <View style={{marginTop: HEADER_HEIGHT, height: 150}}>
      <ScrollView 
        stickyHeaderIndices={[0]} 
          onScroll={event => {
            const y = event.nativeEvent.contentOffset.y;
            if(y >= HEADER_HEIGHT)
              this.setState({
                headerStyle:{
                    ...headerStyle,
                    ...myShadowStyle
                }
              })
            else
              this.setState({
                  headerStyle:{
                      ...headerStyle,
                  }
                })
          }}
      >
        <View style={this.state.headerStyle}>
          <Text>My Header Title</Text>
        </View>
        <Text>Item 1</Text>
        <Text>Item 2</Text>
        <Text>Item 3</Text>
        <Text>Item 4</Text>
        <Text>Item 5</Text>
        <Text>Item 6</Text>
        <Text>Item 7</Text>  
        <Text>Item 8</Text>
        <Text>Item 9</Text>
        <Text>Item 10</Text>
        <Text>Item 11</Text>
        <Text>Item 12</Text>
        <Text>Item 13</Text>
        <Text>Item 14</Text>
      </ScrollView>
    </View>
    );
  }
}
0

Thnx me later..! The final code should be looking like this. This is the most basic example that we can have to dig into animations using react-native.

import React, { useRef } from "react";
import {
  SafeAreaView,
  StyleSheet,
  Text,
  Dimensions,
  Animated,
  View,
} from "react-native";
import Colors from "../../../../config/color/color";

const App = () => {
  const scrollPosition = useRef(new Animated.Value(0)).current;
  const minHeaderHeight = 70;
  const maxHeaderHeight = 200;

  const headerHeight = scrollPosition.interpolate({
    inputRange: [0, 500],
    outputRange: [maxHeaderHeight, minHeaderHeight],
    extrapolate: "clamp",
  });
  const opacity = scrollPosition.interpolate({
    inputRange: [0, 100, 200],
    outputRange: [1, 0.5, 0],
    extrapolate: "clamp",
  });
  const size = scrollPosition.interpolate({
    inputRange: [0, 100, 200, 300, 400],
    outputRange: [20, 17, 15, 13, 11],
    extrapolate: "clamp",
  });
  const imageHeight = scrollPosition.interpolate({
    inputRange: [0, 400],
    outputRange: [100, 50],
    extrapolateLeft: "identity",
    extrapolateRight: "clamp",
  });
  const imagePosition = scrollPosition.interpolate({
    inputRange: [0, 400],
    outputRange: [(37 * Dimensions.get("window").width) / 100, 0],
    extrapolateLeft: "identity",
    extrapolateRight: "clamp",
  });
  return (
    <SafeAreaView>
      <View>
        <Animated.View
          style={{
            // position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            zIndex: 10,
            height: headerHeight,
            backgroundColor: "lightblue",
          }}
        >
          <Animated.Text
            style={{
              opacity: opacity,
              fontSize: size,
            }}
          >
            Header
          </Animated.Text>
          <Animated.Image
            style={{
              height: imageHeight,
              width: imageHeight,
              borderRadius: imageHeight,
              transform: [{ translateX: imagePosition }],
            }}
            source={{
              uri: "https://www.talkwalker.com/images/2020/blog-headers/image-analysis.png",
            }}
          />
        </Animated.View>
        <Animated.ScrollView
          onScroll={Animated.event(
            [{ nativeEvent: { contentOffset: { y: scrollPosition } } }],
            { useNativeDriver: false }
          )}
          contentInsetAdjustmentBehavior="automatic"
          style={[styles.scrollView]}
        >
          {Array.from(Array(100), (e, key) => {
            return <Text key={key}>Item {key}</Text>;
          })}
        </Animated.ScrollView>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: Colors.lighter,
  },
});

export default App;
asad minhas
  • 147
  • 2
  • 10