Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React native : trying to hide search bar on scroll

i am currently trying to hide my search bar when scrolling.

The components i have on screen are a search bar at the top followed by a horizontal scroll view with tabs, then my flatlist.

with the current implementation, when i load the screen, the search bar is covering the tabs and when i scroll down the search bar hides and the tabs appear.

What i am trying to do is, when i load the screen the search bar, tabs and flatlist should all be visible then when i start scrolling the search bar hides and the tabs and flatlist fill the available space at the top.

Also, another problem i am encountering is when i keep scrolling up the search bar keeps moving up until it disappears.

here is my code:

const scrollY = new Animated.Value(0)
const diffClamp=Animated.diffClamp(scrollY,0,100)
const translateY = diffClamp.interpolate({
inputRange:[0,100],
outputRange:[0,-100]
})

return(

<Animated.View style={{transform: 
    [{translateY:translateY}],elevation:4,zIndex:100}}>
    <SearchBar 
     containerStyle={{height:40,marginBottom:20,position:"absolute",
     left:0,right:0,top:0}} 
    inputContainerStyle={{height:40}}
    />
    </Animated.View>

    <View style={{paddingHorizontal:6}}>
    <ScrollView 
    horizontal 
    style={{
    marginBottom:10,
    height:30,
    }} 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map(e=>(
            <TouchableOpacity 
            style={[
                {paddingHorizontal:10,paddingBottom:0},
                label===e.label && 
                {
                borderRadius:2,
                marginBottom:-20,
            }
                ]} 
                onPress={()=>}
                >
            <AppText>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView>
    </View>
    <FlatList
      data={posts} // to have all the data
      keyExtractor={(post) => post.id.toString()}
      renderItem={({ item,index }) => (
       <Card
          title={item.title}
          subTitle={item.subTitle}
        />
      )}
      onScroll={(e)=>{
          scrollY.setValue(e.nativeEvent.contentOffset.y)
      }}
    />
)

with position:"absolute", the search bar is on top on the tabs so instead of position:"absolute" i tried "relative", when i scroll down the search bar hides but there is blank space above the tabs.

I am also using the react native elements search bar component.

would appreciate any help possible, thank you in advance.

UPDATE

After following J.Doe solution, which is the correct solution to solving the translation problem, i now faced a new problem correlating to this.

Since i can toggle between the different tabs in my scrollView, each tab has its corresponding Flatlist data. If the FlatList has more than 3 data items the functionality works correct, but if it has 1 or 2 data items then the translation functionality stops working.

if i am on tab 1 (with many data items) and scroll down (ie. search bar is translated) then tap on tab 2 that only contains 1 data item, i am not able to scroll the screen to see the search bar.

Here is my code:

const categories = [
{
  label: "Sports",
  id: 1,
},
{
  label: "News",
  id: 2,
},
{
  label: "Food",
  id: 3,
},
]

const[label,setLabel]=useState(categories[0]?.label)

const [currentCategoryId, setCurrentCategoryId] = useState(1)

const setLabelFilter=label=>{
setLabel(label)
}

const toggleBrands = (categoryId) => {
setCurrentCategoryId(categoryId)
};

Here is my scrollView:

<ScrollView 
    horizontal 
    style={{
    flexDirection:"row",
    alignContent:"center",
    marginTop: 20,// space between tabs and search bar
    height:30,
    }} 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map((e)=>(
            <TouchableOpacity 
                key={e.id}
                onPress={()=>{
                    toggleBrands(e.id),
                    setLabelFilter(e.label)
                    }}
                selected={e.id === currentCategoryId}
                >
            <AppText style={[{fontWeight:"500"},label===e.label && {fontWeight:"700"}]}>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView> 
like image 937
kd12345 Avatar asked Sep 10 '25 09:09

kd12345


1 Answers

import React from 'react';
import {
  View,
  Animated,
  Text,
  StyleSheet,
  ScrollView,
  RefreshControl,
} from 'react-native';

const data = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];

const App = () => {
  const scrollY = React.useRef(new Animated.Value(0)).current;
  const diffClamp = Animated.diffClamp(scrollY, 0, 100);

  const translateY = diffClamp.interpolate({
    inputRange: [0, 100],
    outputRange: [0, -60],
    extrapolate: 'clamp',
  });

  const marginTop = diffClamp.interpolate({
    inputRange: [0, 100],
    outputRange: [0, -60],
    extrapolate: 'clamp',
  });

  const paddingTop = diffClamp.interpolate({
    inputRange: [0, 100],
    outputRange: [10, 110],
    extrapolate: 'clamp',
  });

  const opacity = diffClamp.interpolate({
    inputRange: [0, 100],
    outputRange: [1, 0],
    extrapolate: 'clamp',
  });

  const renderItem = ({item}) => {
    return (
      <View style={styles.card}>
        <Text>{`Card ${item}`}</Text>
      </View>
    );
  };

  return (
    <View style={{flex: 1, backgroundColor: 'red'}}>
      <Animated.View
        style={{
          zIndex: 100,
          paddingBottom: 10,
          transform: [{translateY}],
        }}>
        <Animated.View style={[styles.searchBar, {opacity}]}>
          <Text>Search Bar</Text>
        </Animated.View>
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          {data.map((num) => {
            return (
              <View key={num} style={styles.tab}>
                <Text>Tab</Text>
              </View>
            );
          })}
        </ScrollView>
      </Animated.View>
      <Animated.FlatList
        style={{marginTop, paddingTop}}
        // contentContainerStyle={{paddingTop: 150}}
        refreshControl={
          <RefreshControl
            tintColor="#fff"
            onRefresh={() => {
              console.warn('Refreshing');
            }}
            refreshing={false}
          />
        }
        bounces={true}
        data={data}
        keyExtractor={(item) => item}
        scrollEventThrottle={16}
        renderItem={renderItem}
        onScroll={(e) => {
          if (e.nativeEvent.contentOffset.y > 0)
            scrollY.setValue(e.nativeEvent.contentOffset.y);
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  searchBar: {
    marginHorizontal: '5%',
    width: '90%',
    marginTop: 40,
    height: 40,
    borderRadius: 10,
    borderColor: 'lightgray',
    borderWidth: 1,
    backgroundColor: '#f4f4f4',
    justifyContent: 'center',
    alignItems: 'center',
  },
  tab: {
    justifyContent: 'center',
    alignItems: 'center',
    marginTop: 20,
    marginHorizontal: 20,
    width: 70,
    height: 30,
    borderRadius: 10,
    backgroundColor: 'pink',
  },
  card: {
    width: '90%',
    marginLeft: '5%',
    height: 100,
    borderRadius: 10,
    backgroundColor: 'yellow',
    marginBottom: 20,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;
like image 145
Leri Gogsadze Avatar answered Sep 13 '25 00:09

Leri Gogsadze