Search code examples
javascriptreact-nativeanimationtransition

React Native - Animate width shrink


In the header of my React Native app, I have a conditional icon and a Searchbar.

static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
  headerTitle: (
    <View
      style={{
        flex: 1,
        backgroundColor: Platform.OS === 'ios' ? '#e54b4d' : '',
        alignItems: 'center',
        flexDirection: 'row',
        paddingHorizontal: 10,
        height: StatusBar.currentHeight,
      }}>
      {params.isIconTriggered && <Icon name="chevron-left" size={28} />}
      <SearchBar
        round
        platform={'default'}
        placeholder="Search"
        containerStyle={{
          flex: 1,
          backgroundColor: 'transparent',
        }}
      />
    </View>
  ),
  headerStyle: {
    backgroundColor: '#e54b4d',
  },
};
};

Normally the Searchbar will take the full width of the header which is what I want. If the condition isIconTriggered is true, an icon will appear in front of the Searchbar and the width of the SearchBar will shrink enough so that the icon is visible next to it.

However, there is no transition or animation when this happens and it does not feel nor look nice. I would like to add an animation to the Searchbar so the width shrinks gradually and smoothly when the condition is triggered and the icon appears.

Is that possible to achieve and how can I achieve this?


Solution

  • Try to learn Animated API of react native.

    Here is how i done it with button trigger.

    here is the preview

    import React, {Component} from 'react';
    import {StyleSheet, View, TextInput , Button, SafeAreaView, Animated} from 'react-native';
    import FA from 'react-native-vector-icons/FontAwesome5'
    
    const AnimatedIcon = Animated.createAnimatedComponent(FA)
    // make your icon animatable using createAnimatedComponent method
    
    export default class Application extends Component {
    
      animVal = new Animated.Value(0);
       // initialize animated value to use for animation, whereas initial value is zero
    
      interpolateIcon = this.animVal.interpolate({inputRange:[0,1], outputRange:[0,1]})
      interpolateBar = this.animVal.interpolate({inputRange:[0,1],outputRange:['100%','90%']})
      // initialize interpolation to control the output value that will be passed on styles
      // since we will animate both search bar and icon. we need to initialize both 
      // on icon we will animate the scale whereas outputRange starts at 0 end in 1
      // on search bar we will animate width. whereas outputRange starts at 100% end in 90%
    
      animatedTransition = Animated.spring(this.animVal,{toValue:1})
      // we use spring to make the animation bouncy . and it will animate to Value 1
    
      clickAnimate = () => {
        this.animatedTransition.start()
      }
      // button trigger for animation
    
      //Components that will use on Animation must be Animated eg. Animted.View
      render() {
        return (
          <SafeAreaView>
          <View style={styles.container}>
            <View style={styles.search}>
            {/* our icon */}
    
            <Animated.View style={{width: this.interpolateBar}}>
            <TextInput placeholder='search here' style={styles.input}/>
            </Animated.View>
    
            <AnimatedIcon name='search' size={28} style={{paddingLeft: 10,paddingRight:10, transform:[{scale: this.interpolateIcon}]}}/>
            </View>
    
              <Button title='animate icon' onPress={this.clickAnimate}/>
          </View>
          </SafeAreaView>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        backgroundColor:'#F79D42',
        // flex: 1,
        height:'100%',
        paddingTop:20,
        flexDirection: 'column',
        // justifyContent: 'center',
        alignItems:'center'
      },
      input:{
        width: '100%',
        height:40,
        backgroundColor:'gray',
        textAlign:'center'
      },
      search:{
        flexDirection:'row-reverse',
        width:'90%',
        height:40,
        alignItems:'center'
      }
    });
    

    Solution using react-native-elements SearchBar component. Wrapped the SearchBar Component inside Animated.View. to explicitly animate the search bar

    Like This:

     <Animated.View style={{width: this.interpolateBar}}>
        <SearchBar
        placeholder="Type Here..."
        containerStyle={{width: '100%'}}
      />
        </Animated.View>
    

    enter image description here