【搭建react-native项目框架】4.自定义TabBar中间按钮,实现播放时旋转动画

关于如何集成TabBar,请看上一节《【搭建react-native项目框架】3.集成第三方路由和tab页》

本节只讲解如何自定义TabBar的中间按钮,以及播放时旋转动画的实现。

关于动画与播放器的集成可以参考https://github.com/pheromone/react-native-videoDemo,但这个项目目前安卓存在bug,所以我只借鉴了动画部分。

还是先来看效果图

【搭建react-native项目框架】4.自定义TabBar中间按钮,实现播放时旋转动画_第1张图片

其实思路很简单,首先要使TabBar把中间按钮的位置空出来,然后摆上一个悬浮的按钮,就能实现中间按钮了。

1.设置CustomTabBar的placeMiddle属性为true,这个属性表示是否把中间按钮的位置留出来。

                    

 

2.悬浮效果可以用绝对定位来实现,见下图

【搭建react-native项目框架】4.自定义TabBar中间按钮,实现播放时旋转动画_第2张图片

在components下新建一个playButton.js文件。先写一个外层View,绝对定位到页面底部中间位置;再做个带边框的圆形View;然后用长方形View将圆形View下半部的边框覆盖;最后写个旋转图和按钮。

                
                    
                    
                     this.play()} underlayColor="transparent" style={[styles.playInner]}>
                        
                            
                            
                        
                    
                

 

const styles = StyleSheet.create({
    playBox: {
        width: Common.autoScaleSize(128),
        height: Common.autoScaleSize(136),
        position: 'absolute',
        bottom: 0,
        left: Common.autoScaleSize(311),
        flexDirection: 'column',
        justifyContent: 'flex-start',
        alignItems: 'center',
    },
    playBoxCircle: {
        backgroundColor: '#ffffff',
        width: Common.autoScaleSize(128),
        height: Common.autoScaleSize(128),
        borderRadius: Common.autoScaleSize(128),
        position: 'absolute',
        bottom: Common.autoScaleSize(8),
        borderWidth: Common.autoScaleSize(1),
        borderColor: '#cdcdcd',
    },
    playBoxBackground: {
        backgroundColor: '#ffffff',
        width: Common.autoScaleSize(125),
        height: Common.autoScaleSize(72),
        position: 'absolute',
        bottom: 0,
        left: Common.autoScaleSize(1),
    },
    playInner: {
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        position: 'absolute',
        bottom: Common.autoScaleSize(20),
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
    },
    playInnerBox: {
        backgroundColor: '#cdcdcd',
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
    },
    playBackImage: {
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        position: 'absolute',
    },
});

3.实现旋转动画。

先构造初始旋转角度、播放状态和旋转动画

        this.state = {
            playImage: require('./resources/images/play.png'),
            rotateValue: new Animated.Value(0), //旋转角度的初始值
        };
        this.isPlaying = false;
        this.playerAnimated = Animated.timing(this.state.rotateValue, {
            toValue: 1, //角度从0变1
            duration: 15000, //从0到1的时间
            easing: Easing.inOut(Easing.linear), //线性变化,匀速旋转
        });

根据播放状态切换播放按钮的图标,并开始/暂停播放

    play() {
        this.isPlaying = !this.isPlaying;
        if (this.isPlaying === true) {
            this.setState({
                playImage: require('./resources/images/pause.png'),
            });
            this.startPlay();
        } else {
            this.setState({
                playImage: require('./resources/images/play.png'),
            });
            this.stopPlay();
        }
    }

开始播放

    startPlay() {
        this.playerAnimated.start(() => {
            this.playerAnimated = Animated.timing(this.state.rotateValue, {
                toValue: 1, //角度从0变1
                duration: 15000, //从0到1的时间
                easing: Easing.inOut(Easing.linear), //线性变化,匀速旋转
            });
            this.rotating();
        });
    }

暂停播放

    stopPlay() {
        this.state.rotateValue.stopAnimation((oneTimeRotate) => {
            //计算角度比例
            this.playerAnimated = Animated.timing(this.state.rotateValue, {
                toValue: 1,
                duration: (1-oneTimeRotate) * 15000,
                easing: Easing.inOut(Easing.linear),
            });
        });
    }

开始旋转动画

    rotating() {
        if (this.isPlaying) {
            this.state.rotateValue.setValue(0);
            this.playerAnimated.start(() => {
                this.rotating()
            })
        }
    };

4.在App.js文件中引入playButton.js

import PlayButton from "./components/playButton";

在最外层View组件底部渲染PlayButton

            
                //Router......
                
            

 

最后上完整的playButton.js代码

import React, { Component } from 'react';
import {
    Animated,
    Easing,
    StyleSheet,
    View,
    TouchableOpacity,
    Image,
} from "react-native";
//自定义组件
import Common from "./common";
//页面
import PlayScreen from '../views/play'; //播放页

export default class PlayButton extends Component {
    constructor(props) {
        super(props);
        //使用Animated.Value设定初始化值(角度)
        this.state = {
            playImage: require('../resources/images/play.png'),
            rotateValue: new Animated.Value(0), //旋转角度的初始值
        };
        this.isPlaying = false;
        this.playerAnimated = Animated.timing(this.state.rotateValue, {
            toValue: 1, //角度从0变1
            duration: 15000, //从0到1的时间
            easing: Easing.inOut(Easing.linear), //线性变化,匀速旋转
        });
    }

    play() {
        this.isPlaying = !this.isPlaying;
        if (this.isPlaying === true) {
            this.setState({
                playImage: require('../resources/images/pause.png'),
            });
            this.startPlay();
        } else {
            this.setState({
                playImage: require('../resources/images/play.png'),
            });
            this.stopPlay();
        }
    }

    rotating() {
        if (this.isPlaying) {
            this.state.rotateValue.setValue(0);
            this.playerAnimated.start(() => {
                this.rotating()
            })
        }
    };

    startPlay() {
        this.playerAnimated.start(() => {
            this.playerAnimated = Animated.timing(this.state.rotateValue, {
                toValue: 1, //角度从0变1
                duration: 15000, //从0到1的时间
                easing: Easing.inOut(Easing.linear), //线性变化,匀速旋转
            });
            this.rotating();
        });
    }

    stopPlay() {
        this.state.rotateValue.stopAnimation((oneTimeRotate) => {
            //计算角度比例
            this.playerAnimated = Animated.timing(this.state.rotateValue, {
                toValue: 1,
                duration: (1-oneTimeRotate) * 15000,
                easing: Easing.inOut(Easing.linear),
            });
        });
    }

    render() {
        return (
            
                
                
                 this.play()} underlayColor="transparent" style={[styles.playInner]}>
                    
                        
                        
                    
                
            
        );
    }
}

const styles = StyleSheet.create({
    playBox: {
        width: Common.autoScaleSize(128),
        height: Common.autoScaleSize(136),
        position: 'absolute',
        bottom: 0,
        left: Common.autoScaleSize(311),
        flexDirection: 'column',
        justifyContent: 'flex-start',
        alignItems: 'center',
    },
    playBoxCircle: {
        backgroundColor: '#ffffff',
        width: Common.autoScaleSize(128),
        height: Common.autoScaleSize(128),
        borderRadius: Common.autoScaleSize(128),
        position: 'absolute',
        bottom: Common.autoScaleSize(8),
        borderWidth: Common.autoScaleSize(1),
        borderColor: '#cdcdcd',
    },
    playBoxBackground: {
        backgroundColor: '#ffffff',
        width: Common.autoScaleSize(128),
        height: Common.autoScaleSize(101),
        position: 'absolute',
        bottom: 0,
    },
    playInner: {
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        position: 'absolute',
        bottom: Common.autoScaleSize(20),
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
    },
    playInnerBox: {
        backgroundColor: '#cdcdcd',
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
    },
    playBackImage: {
        width: Common.autoScaleSize(101),
        height: Common.autoScaleSize(101),
        borderRadius: Common.autoScaleSize(101),
        position: 'absolute',
    },
});

 

另外,我还仿照少年得到app的方式做了交互式按钮的demo,感兴趣的同学不妨去看看。

你可能感兴趣的:(【搭建react-native项目框架】4.自定义TabBar中间按钮,实现播放时旋转动画)