欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

React Native 加载动画

程序员文章站 2022-05-03 09:47:53
...

第一步:屏蔽react-navigation默认的过渡动画

    在创建createStackNavigator的时候,我们可以设置其相应的属性值,其中有一个transitionConfig的属性。官方解释为它是一个用于返回屏幕过渡对象的函数,该对象中也包含了其他的属性,如下:

/**
   * Describes a visual transition from one screen to another.
   */
  declare export type TransitionConfig = {
    // The basics properties of the animation, such as duration and easing
    transitionSpec?: NavigationTransitionSpec,
    // How to animate position and opacity of the screen
    // based on the value generated by the transitionSpec
    screenInterpolator?: (props: NavigationSceneRendererProps) => {},
    // How to animate position and opacity of the header componetns
    // based on the value generated by the transitionSpec
    headerLeftInterpolator?: (props: NavigationSceneRendererProps) => {},
    headerTitleInterpolator?: (props: NavigationSceneRendererProps) => {},
    headerRightInterpolator?: (props: NavigationSceneRendererProps) => {},
    // The style of the container. Useful when a scene doesn't have
    // 100% opacity and the underlying container is visible.
    containerStyle?: ViewStyleProp,
  };

   其中我们可以看一下screenInterpolator的作用,它是用来配置屏幕过渡动画的。因为我们需要实现特殊的屏幕过渡动画效果,那么我恩需要将默认的过渡动画给取消掉,代码如下:

const TransitionConfiguration = () => ({
    screenInterpolator: (sceneProps) => {
        const {scene} = sceneProps
        const {route} = scene
        const params = route.params || {}
        const routeName = sceneProps.scene.route.routeName
        const transition = params.transition || 'forHorizontal'
        if (routeName === 'SecondPage'){ \\当进入SecondPage页面的时候,取消默认的过渡动画
            return null
        }
        return StackViewStyleInterpolator[transition](sceneProps)
    },
    transitionSpec: {
        duration: 350,
        easing: Easing.out(Easing.poly(4)),
        timing: Animated.timing,
    }
})
const StackNavigatorConfig = {
    initialRouteName:'FirstPage',
    headerMode: 'screen',
    mode:'card',
    transitionConfig: TransitionConfiguration,
}

同时我们需要注意一下StackViewStyleInterpolator的引用:

在react-navigation 2.11.2之前:

import StackViewStyleInterpolator from 'react-navigation/src/views/StackView/StackViewStyleInterpolator'

在react-navigation 2.11.2之后:

import StackViewStyleInterpolator from 'react-navigation-stack/dist/views/StackView/StackViewStyleInterpolator'

第二步:自定义过渡动画

这一步我们需要根据实际的场景来实现,一般由设计师来决定。其实我们是没有办法自定义这个过渡动画的,除非去修改源码,但是那样做的难度和风险都比较大,为了实现这样的效果,我只是在第一个页面过渡之前加载了一段动画,在动画结束之后再进行跳转,因为取消了react-navigation默认的过渡动画,所以可以快速的展示出第二个页面。同时为了保证整个过渡过程的流畅性,第一个页面结束时的样子和第二个页面开始时的样子保持一致就OK。

第一个页面的动画是在点击了某一个item之后,在页面的最上面一层添加一个全屏的View进行动画,跟ListView没有任何关系。你们会发现有一些共用的地方(图片+名称),这其实是使用RN提供的UIManager.measure方法获取到点击事件的位置,然后计算出图标和名称的位置,在最上面一层的View渲染另一个图标和名称,从而做到以假乱真的目的。

因为该过渡动画的重用性不太高,这里就不全部展示出来了。

_startAnimated (rowData, event) {
    this.props.navigation.setParams({enable: true})
    UIManager.measure(event.target, (x, y, width, height, pageX, pageY) => {
      this.setState({
        isShowItemModel: true,
        currentDataSource: rowData,
        currentClickY: pageY - 64,
        showReView: false,
      })
    })
  }

在动画结束之后,执行跳转动作。

this.props.navigation.navigate('SecondPage')

需要注意的是:

   因为上层的View只覆盖了高航栏以下的部分所以导航栏上面的按钮还是可以点击的,所以在执行动画的过程中需要禁止掉按钮点击事件。因为导航按钮是在react-navigation属性中配置的,所以只能在this.props.navigation.params中添加一个变量来控制按钮的点击

static navigationOptions = ({navigation, screenProps}) => ({
        title: 'FirstPage', // 固定标题
        headerRight: <TouchableOpacity style={{marginRight:20}}
                                       disabled={navigation.state.params ? navigation.state.params.disable : false}
                                       onPress={() => {
                                           const {params = {}} = navigation.state
                                           params.showAlert()
        }}><Text style={{fontSize: 14,color: '#333'}}>新增</Text></TouchableOpacity>
    })
componentDidMount () {
        this.props.navigation.setParams({showAlert: this.showAlert.bind(this),disable: false})
    }
goSecondPage() {
        this.props.navigation.setParams({disable: true})
        this.staggerAnimated.start(()=>{
            this.props.navigation.navigate('SecondPage')
            this.props.navigation.setParams({disable: false})
            this.staggerAnimated.reset()
        })
    }