netguru / sticky-parallax-header

A simple React Native library, enabling the creation of fully customized header for your iOS and Android apps.
https://netguru.github.io/sticky-parallax-header/
MIT License
1.86k stars 190 forks source link

How to implement "Scrollable Tabs" like TabbedHeaderPager (Yoda Example) with StickyHeaderScrollView / Custom Header (Sims Example) #407

Open ammarfaris opened 1 year ago

ammarfaris commented 1 year ago

Feature request

I looked at the Yoda and the default HomeScreen Example, it's quite clear to me that the <TabbedHeaderPager /> component has a tabs prop that we can pass the TABS array of tab objects (title and description) and then we can map the items inside the child of the component like so (correct me if i'm wrong):

in Yoda's Screen data.ts:

export const TABS = [
  {
    title: 'Biography',
    description: text.biography,
    testID: yodaScreenTestIDs.contentBiography,
    contentTestID: yodaScreenTestIDs.contentBiography,
  },
  {
    title: 'Powers and Abilities',
    description: text.powers,
    testID: yodaScreenTestIDs.contentPowers,
    contentTestID: yodaScreenTestIDs.contentPowers,
  },
  {
    title: 'Powers and Abilities 2',
    description: text.powers,
    testID: yodaScreenTestIDs.contentPowers,
    contentTestID: yodaScreenTestIDs.contentPowers2,
  },
  {
    title: 'Appearances',
    description: text.appearances,
    testID: yodaScreenTestIDs.contentAppearances,
    contentTestID: yodaScreenTestIDs.contentAppearances,
  },
];

and in YodaScreen index.tsx:

 return (
    <>
      <TabbedHeaderPager
        containerStyle={screenStyles.stretchContainer}
        backgroundImage={{
          uri: "https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg",
        }}
        title="Baby Yoda"
        titleStyle={styles.titleStyle}
        titleTestID={yodaScreenTestIDs.headerTitle}
        foregroundImage={{
          uri: "https://cdn.iconscout.com/icon/free/png-256/starwars-6-569425.png",
        }}
        tabsContainerBackgroundColor={colors.black}
        tabTextContainerStyle={styles.tabTextContainerStyle}
        tabTextContainerActiveStyle={styles.tabTextContainerActiveStyle}
        tabTextStyle={styles.tabText}
        tabTextActiveStyle={styles.tabTextActiveStyle}
        tabWrapperStyle={styles.tabWrapperStyle}
        tabsContainerStyle={styles.tabsContainerStyle}
        onScroll={onScroll}
        tabs={TABS}
        renderHeaderBar={() => <HeaderBar scrollValue={scrollValue} />}
        showsVerticalScrollIndicator={false}
      >
        {TABS.map((tab, i) => (
          <View
            key={i}
            style={[styles.contentContainer, { height: windowHeight }]}
          >
            <Text
              style={[screenStyles.text, styles.contentText]}
              testID={tab.contentTestID}
            >
              {tab.description}
            </Text>
          </View>
        ))}
      </TabbedHeaderPager>
      <StatusBar barStyle="light-content" backgroundColor="black" translucent />
    </>
  );

then we get the nice "Scrollable Tabs": IMG_9716

I am wondering how will we implement this for component / Custom Header (Sims Example):

IMG_9713

Looking at the SimsScreen example code snippet at SimsScreen/index.tsx:

  return (
    <View style={screenStyles.screenContainer}>
      <View style={[styles.headerBarContainer, { width: windowWidth }]}>
        <HeaderBar scrollValue={scrollValue} />
      </View>
      <View style={screenStyles.stretchContainer}>
        <StickyHeaderScrollView
          ref={scrollViewRef}
          containerStyle={screenStyles.stretchContainer}
          onScroll={onScroll}
          onMomentumScrollEnd={onMomentumScrollEnd}
          onScrollEndDrag={onScrollEndDrag}
          renderHeader={() => {
            return (
              <View pointerEvents="box-none" style={{ height: scrollHeight }}>
                <Foreground scrollValue={scrollValue} />
              </View>
            );
          }}
          renderTabs={() => (
            <View style={styles.tabContainer}>
              <Tabs />
            </View>
          )}
          showsVerticalScrollIndicator={false}
          style={screenStyles.stretch}
        >
          <SafeAreaView
            edges={["left", "right", "bottom"]}
            style={styles.content}
          >
            <Text
              style={screenStyles.text}
              testID={simsScreenTestIDs.contentTestID}
            >
              {text}
            </Text>
          </SafeAreaView>
        </StickyHeaderScrollView>
      </View>
      <StatusBar
        barStyle="light-content"
        backgroundColor={colors.black}
        translucent
      />
    </View>
  );

there is a renderTabs prop but it seems like a prop to just render how the Tabs will look like but is disconnected from the content of the tabs:

          renderTabs={() => (
            <View style={styles.tabContainer}>
              <Tabs />
            </View>
          )}

in Tabs.tsx :

export const Tabs: React.FC = () => {
  return (
    <View style={styles.tabsContainer}>
      <Tab title="Tab 1" />
      <Tab title="Tab 2" />
      <Tab title="Tab 3" />
      <Tab title="Tab 4" />
      <Tab title="Tab 5" />
    </View>
  );
};

const Tab: React.FC<{ title: string }> = ({ title }) => {
  return (
    <Pressable
      android_ripple={{
        borderless: false,
        color: colors.paleGrey,
      }}
      style={({ pressed }) => [styles.tab, pressed && styles.pressedTab]}>
      <Text style={[screenStyles.text, styles.tabTitle]}>{title}</Text>
    </Pressable>
  );
};

and in SimsScreen/index.tsx the {text}displayed is just a disconnected static text coming from SimsScreen/data.ts:

SimsScreen/index.tsx:

....
import { text } from "./data";
...
        <StickyHeaderScrollView ...props >
          <SafeAreaView
            edges={["left", "right", "bottom"]}
            style={styles.content}
          >
            <Text
              style={screenStyles.text}
              testID={simsScreenTestIDs.contentTestID}
            >
              {text}
            </Text>
          </SafeAreaView>
        </StickyHeaderScrollView>

SimsScreen/data.ts:

export const text = `
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque facilisis, tellus nec blandit iaculis, velit mi cursus nibh, semper ullamcorper sem eros blandit lacus. Quisque placerat vitae ex eu vestibulum. Phasellus a nibh a eros vestibulum venenatis ut eu ante. Mauris at ligula a mi molestie consequat non ut ipsum. Nulla iaculis sem diam, nec mollis nisi posuere quis. Sed gravida elementum ipsum quis elementum. Integer scelerisque urna id orci vehicula, id rutrum nisi tincidunt. Vivamus accumsan dolor ut ornare interdum. Vestibulum lacus quam, tempus eget volutpat id, rhoncus ac sapien. Nunc elit mauris, vestibulum in cursus eget, elementum vel ligula. Proin ultrices nibh neque, vitae lobortis massa sodales ut. Praesent a nisl vitae tortor pretium maximus. Sed euismod cursus massa et dictum. Nullam quis massa eleifend est semper ornare. Suspendisse justo sem, dictum id convallis in, bibendum et nisl. Quisque scelerisque augue nec venenatis ornare.

Nulla facilisi. Vestibulum tempor varius dolor, non condimentum lorem lacinia eu. Suspendisse dictum luctus facilisis. Suspendisse vehicula eget justo vitae viverra. Aenean eu augue quis massa faucibus auctor et ut metus. Praesent tincidunt risus ut ex convallis, non aliquam tortor euismod. Vestibulum congue, lorem vel vulputate tempus, enim magna eleifend orci, id semper diam orci at lorem. Curabitur eget metus faucibus neque facilisis scelerisque.'

...
`;

Therefore, my main question is How to implement "Scrollable Tabs" like TabbedHeaderPager (Yoda Example) with StickyHeaderScrollView / Custom Header (Sims Example) ?

Not sure if it should be a "feature request" to make the implementation more like TabbedHeaderPager or another implementation with react-native-tab-view (https://reactnavigation.org/docs/tab-view/) (I tried this but does not work so far) , would like to seek help on the implementation because I really like the SImScreen example due to the image stretches to the top of the screen and into the notch and with blur-effect.

Thank you in advance 🙏🏻