PedroBern / react-native-collapsible-tab-view

A cross-platform Collapsible Tab View component for React Native
MIT License
815 stars 161 forks source link

Buggy Tab.ScrollView #363

Closed francoangulo closed 10 months ago

francoangulo commented 10 months ago

Idk if this is a bug or bad application of the library, but I can't find any response in the library docs or in other issues reported. Does anyone have any idea on how to solve this?

https://github.com/PedroBern/react-native-collapsible-tab-view/assets/58487596/e095ad45-7ddc-43eb-a5f2-f9c43a54cc5b

These are the tabs

const RecipeTabs = ({ recipe, insets, header }) => {
  const [branding, { bgColor, textColor }] = useBranding();
  const { t } = useTranslation();

  const { ingredients, steps, nutrients } = recipe;

  const tabs = [
    {
      tabName: t(RECIPES_SCREEN_INGREDIENTS),
      Component: () => <IngredientsTab ingredients={ingredients} />,
    },
    {
      tabName: t(RECIPES_SCREEN_DIRECTIONS),
      Component: () => <DirectionsTab steps={steps} />,
    },
    {
      tabName: t(RECIPES_SCREEN_NUTRITION),
      Component: () => <NutritionTab nutrients={nutrients} />,
    },
  ];

  return (
    <Tabs.Container
      renderHeader={header}
      headerContainerStyle={{ ...bgColor(branding) }}
      containerStyle={{ paddingTop: insets.top }}
      renderTabBar={(props) => (
        <MaterialTabBar
          {...props}
          indicatorStyle={primaryBgColor(branding)}
          style={{ ...props.style, paddingTop: insets.top }}
        />
      )}
    >
      {tabs.map(({ tabName, Component }, idx) => {
        return (
          <Tabs.Tab
            key={`${idx}-${tabName}`}
            name={tabName}
            label={({ name }) => {
              return (
                <Text
                  style={{
                    ...textColor(branding),
                    fontWeight: "700",
                    fontSize: 12,
                  }}
                >
                  {name}
                </Text>
              );
            }}
          >
            <Tabs.ScrollView style={{ padding: 8 }}>
              <Component />
            </Tabs.ScrollView>
          </Tabs.Tab>
        );
      })}
    </Tabs.Container>
  );
};

const styles = StyleSheet.create({
  tab: {
    borderBottomWidth: 1,
  },
  tabText: {
    fontFamily: "OpenSans-Bold",
    fontSize: 12,
  },
  tabContentView: {
    padding: 8,
  },
});

And this is the header

const TabsHeader = () => (
    <View style={{ pointerEvents: "box-none" }}>
      <TouchableOpacity
        style={[
          styles.backButton,
          { top: iOS ? insets.top + 16 : 16 },
          bgColor(branding),
        ]}
        onPress={() => navigation.goBack()}
      >
        <MCIcon
          name="arrow-left"
          style={[styles.backButtonIcon, textColor(branding)]}
          type="MaterialCommunityIcons"
        />
      </TouchableOpacity>
      <View style={{ flex: 1, ...bgColor(branding), pointerEvents: "none" }}>
        <FastImage source={imageSource} style={styles.image} />

        <Text titleOne style={[styles.name, textColor(branding)]}>
          {name}
        </Text>

        <View style={[styles.infoCard, cardBgColor(branding, "elevationTwo")]}>
          <View style={styles.infoRow}>
            <MCIcon
              type="MaterialCommunityIcons"
              name="silverware-fork-knife"
              style={attributeIconStyles}
            />
            <Text style={attributeTextStyles}>
              {servings} {t(RECIPES_SCREEN_SERVINGS)}
            </Text>
          </View>

          <View style={styles.infoRow}>
            <MCIcon
              type="MaterialCommunityIcons"
              name="clock-outline"
              style={attributeIconStyles}
            />
            <Text style={attributeTextStyles}>
              {prepTime.replace("min", t(RECIPES_SCREEN_MIN))}
            </Text>
          </View>

          <View style={styles.infoRow}>
            <MCIcon
              type="MaterialCommunityIcons"
              name="signal-cellular-3"
              style={attributeIconStyles}
            />
            <Text style={attributeTextStyles}>
              {difficultyTranslationHelper[difficulty]}
            </Text>
          </View>
        </View>

        {!!dietaryRestrictions?.length && (
          <View style={[styles.infoCard, styles.infoCardAlt]}>
            {restrictions.map(({ value, icon, text, customLabel }) => {
              if (!dietaryRestrictions.includes(value)) return null;

              return (
                <View key={value} style={styles.infoRow}>
                  {!!text ? (
                    <Text style={[styles.textIcon, textColor(branding)]}>
                      {text}
                    </Text>
                  ) : !!icon ? (
                    icon({ style: attributeIconStyles })
                  ) : null}
                  <Text style={attributeTextStyles}>
                    {customLabel || value}
                  </Text>
                </View>
              );
            })}
          </View>
        )}

        <View style={[styles.infoCard, styles.infoCardAlt]}>
          <View style={styles.infoRow}>
            <Text style={attributeTextStyles}>
              {foodTypeTranslationHelper[foodType]}
            </Text>
          </View>

          <View style={styles.infoRow}>
            <Text style={[styles.textIcon, textColor(branding)]}>Macros:</Text>
            <Text style={attributeTextStyles}>
              {macrosMap[macrosBase] || t(RECIPES_SCREEN_PER_SERVING)}
            </Text>
          </View>
        </View>

        <Text style={[styles.description, textColor(branding, "low")]}>
          {description}
        </Text>
      </View>
    </View>
  );

using react-native-collapsible-tab-view v6.2.0

tiste commented 10 months ago

I experience the same behaviour with expo 49, RNGH 2.12.0, pager view 6.2.0.

tiste commented 10 months ago

Just found I used name property instead of label one, and so the scrolls were struggling. I change name for label and add "A", "B", "C" for my tabs names.

francoangulo commented 10 months ago

Just found I used name property instead of label one, and so the scrolls were struggling. I change name for label and add "A", "B", "C" for my tabs names.

Hi @tiste, could you provide me more details on how you solved this? Like your code before and after solving it? Please I am still fighting with it

tiste commented 10 months ago

I switch from something like

<Tabs.Container
          minHeaderHeight={MIN_HEADER_HEIGHT}
          headerContainerStyle={{
            backgroundColor: theme.colors.backgroundSecondary,
            shadowOpacity: 0,
          }}
          renderHeader={() => (
            <View style={{ marginBottom: spacing.extraSmall }}></View>
          )}
        >
          <Tabs.Tab name={translate("proScreen.tabs.common")}>
            <Tabs.ScrollView>
              <View style={[CONTAINER, PAGE_STYLE]}>
                <Text>{pro.humanOpeningHours}</Text>
              </View>
            </Tabs.ScrollView>
          </Tabs.Tab>
          <Tabs.Tab name={translate("proScreen.tabs.otherFeatures")}>
            <Tabs.ScrollView>
              <View style={[CONTAINER, PAGE_STYLE]}></View>
            </Tabs.ScrollView>
          </Tabs.Tab>
        </Tabs.Container>

to

<Tabs.Container
          minHeaderHeight={MIN_HEADER_HEIGHT}
          headerContainerStyle={{
            backgroundColor: theme.colors.backgroundSecondary,
            shadowOpacity: 0,
          }}
          renderHeader={() => (
            <View style={{ marginBottom: spacing.extraSmall }}></View>
          )}
        >
          <Tabs.Tab name="A" label={translate("proScreen.tabs.common")}>
            <Tabs.ScrollView>
              <View style={[CONTAINER, PAGE_STYLE]}>
                <Text>{pro.humanOpeningHours}</Text>
              </View>
            </Tabs.ScrollView>
          </Tabs.Tab>
          <Tabs.Tab name="B" label={translate("proScreen.tabs.otherFeatures")}>
            <Tabs.ScrollView>
              <View style={[CONTAINER, PAGE_STYLE]}></View>
            </Tabs.ScrollView>
          </Tabs.Tab>
        </Tabs.Container>

I was using name as my label.

francoangulo commented 10 months ago

@tiste thanks for providing this! However, I can't discover the issue, but I'm pretty sure it's related to the Tabs.ScrollView since the behavior disappears when I remove it, but I can't scroll and collapse the header anymore

francoangulo commented 10 months ago

I guess the right behavior should be that the 3 tabs scroll together at the same time and thus when you switch to another tab they are at the same point, or, the header should resize automatically right after switching tabs and before the user scrolls, not after that

tiste commented 10 months ago

@francoangulo try to remove all the boilerplate you could have around, until it works. To discover my issue, I copied/pasted the quickstart in place to check if it's due to lib versions, or my code. Since it was working, I added back little by little my own code until I discovered the name/label fail I did.

francoangulo commented 10 months ago

That was a great suggestion, but I still experience the behavior with the quickstart example

tiste commented 10 months ago

@francoangulo hm... be sure to npm/yarn install correctly the last versions of each lib, maybe remove lockfiles and restart expo/react-native.

francoangulo commented 10 months ago

@tiste that was it! the fix was to upgrade the version of reanimated! (v2.2.0 -> 3.4.2) I've been struggling with this for 2 weeks, thanks a lot hero you saved me!