《React-Native系列》5、RN实现弹出选择界面与动画效果
2016-07-20 21:06
393 查看
今天做了个弹出框,见文章最后图片所示,弹出的时候从屏幕下方弹入,用户选择后又从下方弹出,同时有遮罩效果。
首先,我们是怎么实现弹出框,我这边用的是absolute 绝对定位,包括弹层的覆盖,Dialog的绝对位置。
Dialog的布局在这儿就不说了,flex-box、盒子模型...
那么再来说说动画。
参考:RN动画入门Animated
1、创建一个
<Animated.View style={ styles.mask } >
</Animated.View>
<Animated.View style={[styles.tip , {transform: [{
translateY: this.state.offset.interpolate({
inputRange: [0, 1],
outputRange: [height, (height-aHeight -34)]
}),
}]
}]}>
</Animated.View>
我这里创建了2个,一个是遮罩效果,一个是dialog。
2、Dialog样式编写
此处略,见后面完整代码。
3、动画效果
首先是显示Dialog的动画:
//显示动画
in() {
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0.8,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 1,
}
)
]).start();
}
动画还可以被更复杂地组合,通过一些辅助函数例如
由于我里设计成了2组动画,所以使用了parallel让他们同时执行。
duration:执行时间
easing:Easing的枚举值如下
spring //弹跳
linear //线性
easeInEaseOut //缓入缓出
easeIn //缓入
easeOut //缓出
keyboard //键入
介绍下 interpolate ,官网上说明如下:
在这儿我们在translateY 输入从0到1,高度从height 到 (height-aHeight -34),只是简单的让Dialog在Y方式上移动。
明白了显示动画的原理,动画消失就更简单了。
原理:遮罩层由 0.8的透明度变味 0(不显示),高度再反过来就行(从哪里来,回哪里去) ,代码见下面。
最终实现的效果如下:
完整代码如下:(这里把Dialog封装成了组件,需要使用的话, 在你的页面直接导入,然后通过ref 的方式调用show方法即可)
当然你也可以根据你的需求,修改样式。这里只是说明了一种实现方案。
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
View,
Image,
Text,
TouchableHighlight,
Animated,
Easing,
Dimensions,
} from 'react-native';
import TimerMixin from 'react-timer-mixin';
const {width, height} = Dimensions.get('window');
const navigatorH = 64; // navigator height
const [aWidth, aHeight] = [300, 214];
const [left, top] = [0, 0];
const [middleLeft, middleTop] = [(width - aWidth) / 2, (height - aHeight) / 2 - navigatorH];
const styles = StyleSheet.create({
container: {
position:"absolute",
width:width,
height:height,
left:left,
top:top,
},
mask: {
justifyContent:"center",
backgroundColor:"#383838",
opacity:0.8,
position:"absolute",
width:width,
height:height,
left:left,
top:top,
},
tip: {
width:aWidth,
height:aHeight,
left:middleLeft,
backgroundColor:"#fff",
alignItems:"center",
justifyContent:"space-between",
},
tipTitleView: {
height:55,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
tipTitleText:{
color:"#999999",
fontSize:14,
},
tipContentView: {
width:aWidth,
borderTopWidth:0.5,
borderColor:"#f0f0f0",
height:45,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
tipText:{
color:"#e6454a",
fontSize:17,
textAlign:"center",
},
button: {
height: 45,
backgroundColor: '#fff',
//borderColor: '#e6454a',
//borderWidth: 1,
//borderRadius: 4,
alignSelf: 'stretch',
justifyContent: 'center',
//marginLeft: 10,
//marginRight: 10,
},
buttonText: {
fontSize:17,
color:"#e6454a",
textAlign:"center",
},
gap:{
height:10,
width:aWidth,
backgroundColor:'#383838',
opacity:0.8,
},
});
//console.log('======');
export default class Alert extends Component {
mixins = [TimerMixin];
parent ={};
constructor(props) {
super(props);
this.state = {
offset: new Animated.Value(0),
opacity: new Animated.Value(0),
title: "",
choose1: "",
choose2: "",
hide: true,
};
}
render() {
if(this.state.hide){
return (<View />)
} else {
return (
<View style={styles.container} >
<Animated.View style={ styles.mask } >
</Animated.View>
<Animated.View style={[styles.tip , {transform: [{
translateY: this.state.offset.interpolate({
inputRange: [0, 1],
outputRange: [height, (height-aHeight -34)]
}),
}]
}]}>
<View style={styles.tipTitleView}>
<Text style={styles.tipTitleText}>{this.state.title}</Text>
</View>
<TouchableHighlight style={styles.tipContentView} underlayColor='#f0f0f0' onPress={this.choose.bind(this,this.state.choose1)}>
<Text style={styles.tipText} >{this.state.choose1}</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.tipContentView} underlayColor='#f0f0f0' onPress={this.choose.bind(this,this.state.choose2)}>
<Text style={styles.tipText} >{this.state.choose2}</Text>
</TouchableHighlight>
<View style={styles.gap}/>
<TouchableHighlight style={styles.button} underlayColor='#f0f0f0' onPress={this.iknow.bind(this)}>
<Text style={styles.buttonText}>取消</Text>
</TouchableHighlight>
</Animated.View>
</View>
);
}
}
componentDidMount() {
}
//显示动画
in() {
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0.8,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 1,
}
)
]).start();
}
//隐藏动画
out(){
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 0,
}
)
]).start();
setTimeout(
() => this.setState({hide: true}),
500
);
}
//取消
iknow(event) {
if(!this.state.hide){
this.out();
}
}
//选择
choose(msg) {
//console.log(msg);
if(!this.state.hide){
this.out();
this.parent.setState({sex:msg});
}
}
show(title: string, choose1:string,choose2:string ,obj:Object) {
this.parent = obj;
if(this.state.hide){
this.setState({title: title, choose1: choose1, choose2: choose2, hide: false}, this.in);
}
}
}
首先,我们是怎么实现弹出框,我这边用的是absolute 绝对定位,包括弹层的覆盖,Dialog的绝对位置。
Dialog的布局在这儿就不说了,flex-box、盒子模型...
那么再来说说动画。
参考:RN动画入门Animated
1、创建一个
Animated.Value
<Animated.View style={ styles.mask } >
</Animated.View>
<Animated.View style={[styles.tip , {transform: [{
translateY: this.state.offset.interpolate({
inputRange: [0, 1],
outputRange: [height, (height-aHeight -34)]
}),
}]
}]}>
</Animated.View>
我这里创建了2个,一个是遮罩效果,一个是dialog。
2、Dialog样式编写
此处略,见后面完整代码。
3、动画效果
首先是显示Dialog的动画:
//显示动画
in() {
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0.8,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 1,
}
)
]).start();
}
动画还可以被更复杂地组合,通过一些辅助函数例如
sequence或者
parallel(它们分别用于先后执行多个动画和同时执行多个动画)
由于我里设计成了2组动画,所以使用了parallel让他们同时执行。
duration:执行时间
easing:Easing的枚举值如下
spring //弹跳
linear //线性
easeInEaseOut //缓入缓出
easeIn //缓入
easeOut //缓出
keyboard //键入
介绍下 interpolate ,官网上说明如下:
interpolate(config: InterpolationConfigType)
在更新属性之前对值进行插值。譬如:把0-1映射到0-10。在这儿我们在translateY 输入从0到1,高度从height 到 (height-aHeight -34),只是简单的让Dialog在Y方式上移动。
明白了显示动画的原理,动画消失就更简单了。
原理:遮罩层由 0.8的透明度变味 0(不显示),高度再反过来就行(从哪里来,回哪里去) ,代码见下面。
最终实现的效果如下:
完整代码如下:(这里把Dialog封装成了组件,需要使用的话, 在你的页面直接导入,然后通过ref 的方式调用show方法即可)
当然你也可以根据你的需求,修改样式。这里只是说明了一种实现方案。
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
View,
Image,
Text,
TouchableHighlight,
Animated,
Easing,
Dimensions,
} from 'react-native';
import TimerMixin from 'react-timer-mixin';
const {width, height} = Dimensions.get('window');
const navigatorH = 64; // navigator height
const [aWidth, aHeight] = [300, 214];
const [left, top] = [0, 0];
const [middleLeft, middleTop] = [(width - aWidth) / 2, (height - aHeight) / 2 - navigatorH];
const styles = StyleSheet.create({
container: {
position:"absolute",
width:width,
height:height,
left:left,
top:top,
},
mask: {
justifyContent:"center",
backgroundColor:"#383838",
opacity:0.8,
position:"absolute",
width:width,
height:height,
left:left,
top:top,
},
tip: {
width:aWidth,
height:aHeight,
left:middleLeft,
backgroundColor:"#fff",
alignItems:"center",
justifyContent:"space-between",
},
tipTitleView: {
height:55,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
tipTitleText:{
color:"#999999",
fontSize:14,
},
tipContentView: {
width:aWidth,
borderTopWidth:0.5,
borderColor:"#f0f0f0",
height:45,
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
tipText:{
color:"#e6454a",
fontSize:17,
textAlign:"center",
},
button: {
height: 45,
backgroundColor: '#fff',
//borderColor: '#e6454a',
//borderWidth: 1,
//borderRadius: 4,
alignSelf: 'stretch',
justifyContent: 'center',
//marginLeft: 10,
//marginRight: 10,
},
buttonText: {
fontSize:17,
color:"#e6454a",
textAlign:"center",
},
gap:{
height:10,
width:aWidth,
backgroundColor:'#383838',
opacity:0.8,
},
});
//console.log('======');
export default class Alert extends Component {
mixins = [TimerMixin];
parent ={};
constructor(props) {
super(props);
this.state = {
offset: new Animated.Value(0),
opacity: new Animated.Value(0),
title: "",
choose1: "",
choose2: "",
hide: true,
};
}
render() {
if(this.state.hide){
return (<View />)
} else {
return (
<View style={styles.container} >
<Animated.View style={ styles.mask } >
</Animated.View>
<Animated.View style={[styles.tip , {transform: [{
translateY: this.state.offset.interpolate({
inputRange: [0, 1],
outputRange: [height, (height-aHeight -34)]
}),
}]
}]}>
<View style={styles.tipTitleView}>
<Text style={styles.tipTitleText}>{this.state.title}</Text>
</View>
<TouchableHighlight style={styles.tipContentView} underlayColor='#f0f0f0' onPress={this.choose.bind(this,this.state.choose1)}>
<Text style={styles.tipText} >{this.state.choose1}</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.tipContentView} underlayColor='#f0f0f0' onPress={this.choose.bind(this,this.state.choose2)}>
<Text style={styles.tipText} >{this.state.choose2}</Text>
</TouchableHighlight>
<View style={styles.gap}/>
<TouchableHighlight style={styles.button} underlayColor='#f0f0f0' onPress={this.iknow.bind(this)}>
<Text style={styles.buttonText}>取消</Text>
</TouchableHighlight>
</Animated.View>
</View>
);
}
}
componentDidMount() {
}
//显示动画
in() {
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0.8,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 1,
}
)
]).start();
}
//隐藏动画
out(){
Animated.parallel([
Animated.timing(
this.state.opacity,
{
easing: Easing.linear,
duration: 500,
toValue: 0,
}
),
Animated.timing(
this.state.offset,
{
easing: Easing.linear,
duration: 500,
toValue: 0,
}
)
]).start();
setTimeout(
() => this.setState({hide: true}),
500
);
}
//取消
iknow(event) {
if(!this.state.hide){
this.out();
}
}
//选择
choose(msg) {
//console.log(msg);
if(!this.state.hide){
this.out();
this.parent.setState({sex:msg});
}
}
show(title: string, choose1:string,choose2:string ,obj:Object) {
this.parent = obj;
if(this.state.hide){
this.setState({title: title, choose1: choose1, choose2: choose2, hide: false}, this.in);
}
}
}
相关文章推荐
- ReactNative细节汇总
- code-push 交互式命令行脚本
- 8. react-native-android之----模拟手机百度feed流
- 9. react-native-android之----reactjs基础
- 1. react-native-ios之----20分钟搭建环境
- windows下安装android版reactnative
- React Native 环境配置遇到的坑
- 深入浅出 React Native:使用 JavaScript 构建原生应用
- iOS开发 React-native开发环境配置
- ReactNative 学习第二节 环境搭建
- ReactNative学习 第一节
- node_modules文件名或扩展名太长如何删除
- ReactNative学习
- 关于React Native 网络请求以及变量赋值的问题
- iOS开发——React Native入门总结
- 入职两月半的工作业务总结
- 移动客户端开发快速上手ReactNative的学习路线
- React-Native的项目总结
- React Native 入门环境搭建