skip to Main Content

I don’t have much experience working with React Native so bear with me

I am trying to add an animation to one of my components, a search bar that should change its height when click on.
I wrapped my <SearchComponent> component in <TouchOpacity> however the onPress() method doesn’t work when I click on the component directly. It only works when I click around the margins

see red border in image

Following the example from this SO post

App.js

import React, { useState } from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';


import SearchComponent from './assets/components/SearchComp';
import MapScreen from './assets/screens/MapScreen';


export default function App() {

  const [expanded, setExpanded] = useState(false);

  if (expanded) {
    console.log("dkfjl");
  }

  return (
    <SafeAreaView style={styles.container} >

      <MapScreen />

      <View style={styles.searchContainer} >
        <TouchableOpacity
          onPress={() => {
            setExpanded(!expanded)
          }}>
          <SearchComponent expanded={expanded} />
        </TouchableOpacity>

      </View>

    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  searchContainer: {
    bottom: 0,
    position: 'absolute',
    width: '100%'
  }
})

SearchComponent.js

import React, { useEffect, useState } from 'react'
import { Animated } from 'react-native'
import { TextInput } from 'react-native-paper';


export default function SearchComponent({ expanded = false }) {

    const [search, setSearch] = useState('')

    const [bottom] = useState(new Animated.Value(0))

    useEffect(() => {
        Animated.timing(bottom, {
            toValue: !expanded ? 80 : 10,
            duration: 150,
            useNativeDriver: false
        }).start();
    }, [expanded, bottom]);


    return (
        <Animated.View style={{ bottom, backgroundColor: 'red', borderWidth: 3, borderColor: 'red' }}>
            <TextInput placeholder='Search' defaultValue={search} onChangeText={e => setSearch(e)} style={{
                backgroundColor: 'white', borderTopLeftRadius: 20, borderTopRightRadius: 20, borderBottomLeftRadius: 20, borderBottomRightRadius: 20
            }} />
        </Animated.View>
    )
}

2

Answers


  1. Chosen as BEST ANSWER

    I attempted @Vibhor's answer but I was still getting the same problem; pressing directly on the search bar would not trigger an event. Instead I decided to completely remove TouchableOpacity and let the TextInput handle the event

    new App.js (as suggested by @Vibhor)

    export default function App() {
    
      const [expanded, setExpanded] = useState(false);
    
      if (expanded) {
        console.log("dkfjl");
      }
    
      return (
        <SafeAreaView style={styles.container} >
    
          <MapScreen />
    
          <View style={styles.searchContainer} >
            <SearchComponent expanded={expanded} setExpanded={setExpanded} />
            <ExpandedView expanded={expanded} />
    
          </View>
    
        </SafeAreaView>
      );
    }

    updated SearchComponent.js

    export default function SearchComponent({ expanded = false, setExpanded }) {
    
        const [search, setSearch] = useState('')
    
        const [bottom] = useState(new Animated.Value(0))
    
        useEffect(() => {
            Animated.timing(bottom, {
                toValue: !expanded ? 80 : 10,
                duration: 150,
                useNativeDriver: false
            }).start();
        }, [expanded, bottom]);
    
    
        return (
            <Animated.View style={{ bottom, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', backgroundColor: 'white' }}>
                <Icon name="ios-search" style={{ fontSize: 25, paddingRight: 10 }} />
    
                // update state in `onPressIn()`
                <TextInput onPressIn={() => setExpanded(!expanded)} underlineColor='transparent' placeholder='Search' defaultValue={search} onChangeText={e => setSearch(e)} style={{
                    backgroundColor: 'white', borderTopLeftRadius: 20, borderTopRightRadius: 20, borderBottomLeftRadius: 20, borderBottomRightRadius: 20,
                }} />
            </Animated.View>
        )
    }


  2. You are wrapping <SearchComponent/> with TouchableOpacity which is not the right way of doing it. You will have to use TouchableOpacity inside of your SearchComponent.js.

    Your updated App.js should look like this,

    import React, { useState } from "react";
    import { StyleSheet, TouchableOpacity, View } from "react-native";
    import { SafeAreaView } from "react-native-safe-area-context";
    
    import SearchComponent from "./assets/components/SearchComp";
    import MapScreen from "./assets/screens/MapScreen";
    
    export default function App() {
      const [expanded, setExpanded] = useState(false);
    
      if (expanded) {
        console.log("dkfjl");
      }
    
      return (
        <SafeAreaView style={styles.container}>
          <MapScreen />
    
          <View style={styles.searchContainer}>
            // Remove TouchableOpacity from here
            <SearchComponent
              expanded={expanded}
              setExpanded={(val) => setExpanded(val)} // Passed the state as props to update it from child component
            />
          </View>
        </SafeAreaView>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
      },
      searchContainer: {
        bottom: 0,
        position: "absolute",
        width: "100%",
      },
    });
    

    And inside of your SearchComponent.js, you will use your TouchableOpacity and update the value of setExpanded like so,

    import React, { useEffect, useState } from 'react';
    import { Animated,  TouchableOpacity } from 'react-native';
    import { TextInput } from 'react-native-paper';
    
    export default function App({ expanded = false, setExpended }) {
      const [search, setSearch] = useState('');
    
      const [bottom] = useState(new Animated.Value(0));
    
      useEffect(() => {
        Animated.timing(bottom, {
          toValue: !expanded ? 80 : 10,
          duration: 150,
          useNativeDriver: false,
        }).start();
      }, [expanded, bottom]);
    
      return (
        <Animated.View
          style={{
            bottom,
            backgroundColor: 'red',
            borderWidth: 3,
            borderColor: 'red',
          }}>
          <TouchableOpacity onPress={()=>setExpended(!expanded) }>
            <TextInput
              placeholder="Search"
              defaultValue={search}
              onChangeText={(e) => setSearch(e)}
              style={{
                backgroundColor: 'white',
                borderTopLeftRadius: 20,
                borderTopRightRadius: 20,
                borderBottomLeftRadius: 20,
                borderBottomRightRadius: 20,    
              }}
            />
          </TouchableOpacity>
        </Animated.View>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search