React Native - 缩小宽度动画

13

在我的React Native应用程序的标题中,我有一个有条件的图标和一个搜索栏(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',
  },
};
};

通常情况下,搜索栏将占用标题的整个宽度,这正是我想要的。如果条件isIconTriggered为真,则会在搜索栏前出现一个图标,并且搜索栏的宽度将缩小到足以使图标可见。

然而,在此过程中没有转换或动画效果,感觉和外观都不好。我想给搜索栏添加动画,使其在条件被触发并出现图标时逐渐平滑地缩小宽度。

是否有可能实现这一点,如何实现?


你是否使用任何样式库,例如 styled-components - Sergio Escudero
@SergioEscudero 我不使用任何样式库。 - EDJ
3个回答

17

尝试学习React Native的Animated API。

以下是我使用按钮触发完成的方法。

这是预览

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'
  }
});
使用 react-native-elements 的 SearchBar 组件解决方案。 将 SearchBar 组件包装在 Animated.View 中, 以明确地对搜索栏进行动画处理。
像这样:
 <Animated.View style={{width: this.interpolateBar}}>
    <SearchBar
    placeholder="Type Here..."
    containerStyle={{width: '100%'}}
  />
    </Animated.View>

enter image description here


我还没有尝试过react-native-elements库。你能否使用宽度/高度属性代替flex? - Mervzs
我能想到的解决方案是将搜索栏组件包装在Animated.View中,这样它就可以明确地进行动画处理,而不需要修改搜索栏组件的属性。我已经更新了我的答案。 - Mervzs
1
我发现我实现了与此完全相同的东西,但是对于我来说,动画非常卡顿,因为我们无法使用本机驱动程序来布局属性。你是如何让它如此流畅的? - Sami
@Sami,我在这个例子中没有看到useNativeDriver的提及,所以我认为它是流畅的,因为JS线程在那个最小的例子中没有忙碌。我发现你可以使用LayoutAnimation(https://facebook.github.io/react-native/docs/layoutanimation)来让本地驱动程序驱动布局动画。如果全局动画不适合您的风格,您还可以查看Reanimated中的新转换API。 - Daniel Schlaug
是的,我想那就是答案。我尝试过使用LayoutAnimations,但在关闭键盘和使用Layout Animations时会出现问题,否则它本来是完美的 :) 我将开始研究reanimated库。我们已经在另一个库中使用它了,而且使用reanimated进行动画似乎在各个方面都更加优越。 - Sami
显示剩余2条评论

1
你可以使用 React Native 的 Animated API 来实现这一点。
你可以查看这个 教程,了解如何使用动画来改变元素的大小。

-1

React-Native-Animatable非常酷!试试这个:

  1. 创建自定义动画对象
import * as Animatable from 'react-native-animatable';

Animatable.initializeRegistryWithDefinitions({
   const myAnimation = {
      from: {
          width: 200 
      },
      to: {
          width: 100
      }
   }
})
  • 将其用作视图中的动画值或函数调用中的引用。

    在视图内部:

  •    <Animatable.View useNativeDriver animation={myAnimation}/>
    
    

    作为引用变量:
       <Animatable.View useNativeDriver ref={ref=>(this.testAnimation = ref)}/>
    
    

    方法:

       testMethod = () => {
           this.testAnimation.myAnimation();
       }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接