React Native 通过近两年的迭代和维护,最新版本已经到了 0.45.1,关于最新版本的介绍请查看我之前的博客:0.45 新特性。话说回来,尽管迭代的挺快,但还是有很多坑,很多基础的组件和 API 还是不完善。
今天给大家带来的自定义小专题,其实对于 React Native 来说,自定义组件的过程更像是 Android、iOS 的组合控件。大体步骤有如下几个步骤(不完全准确,但是方向大体准确): 1,定义构造函数 constructor; 2,定义组件属性 propTypes; 3,绘制界面; 4,添加更新界面逻辑等
在系统组件中,RN 为我们提供了 ToastAndroid 组件,但是对于 iOS 好像并没有直接提供,这时候我们就想到了自定义控件了。如下图所示:
我们之前讲过 Animated 组件,这个组件可以实现渐变,缩放,旋转等动画效果,在这里,我们可以用它来实现 Toast 的功能。比如,显示两秒后消失,为了对显示的位置进行设置,我们还可以设置显示的位置,所以绘制 render 的代码如下:
- render() {lettop;switch(this.props.position){case 'top':
- top=160;break;case 'center':
- top=height /2;break;case 'bottom':
- top=height -160;break;
- }letview =this.state.isShow"none">this.state.opacityValue}]}
- >
- {this.state.text}
- :null;returnview;
- }
显示时长控制方法:
- show(text, duration) {
- if(duration>=DURATION.LENGTH_LONG){
- this.duration=DURATION.LENGTH_LONG;}else {
- this.duration=DURATION.LENGTH_SHORT;}
- this.setState({
- isShow: true,
- text: text,
- });this.isShow=true;this.state.opacityValue.setValue(OPACITY)
- this.close();}
完整代码:
- /**
- * Sample React Native App
- * https://github.com/facebook/react-native
- * @flow
- */
- import React,
- {
- Component,
- PropTypes
- }
- from 'react';
- import {
- StyleSheet,
- View,
- Animated,
- Dimensions,
- Text,
- }
- from 'react-native'export const DURATION = {
- LENGTH_LONG: 2000,
- LENGTH_SHORT: 500
- };
- const {
- height,
- width
- } = Dimensions.get('window');
- const OPACITY = 0.6;
- const dismissKeyboard = require('dismissKeyboard') export
- default class ToastUtil extends Component {
- static propTypes = {
- position: PropTypes.oneOf(['top', 'center', 'bottom', ]),
- }
- static defaultProps = {
- position: 'center',
- }
- constructor(props) {
- super(props);
- this.state = {
- isShow: false,
- text: '',
- opacityValue: new Animated.Value(OPACITY),
- }
- }
- show(text, duration) {
- if (duration >= DURATION.LENGTH_LONG) {
- this.duration = DURATION.LENGTH_LONG;
- } else {
- this.duration = DURATION.LENGTH_SHORT;
- }
- this.setState({
- isShow: true,
- text: text,
- });
- this.isShow = true;
- this.state.opacityValue.setValue(OPACITY) this.close();
- }
- close() {
- if (!this.isShow) return;
- this.timer && clearTimeout(this.timer);
- this.timer = setTimeout(() = >{
- Animated.timing(this.state.opacityValue, {
- toValue: 0.0,
- duration: 1000,
- }).start(() = >{
- this.setState({
- isShow: false,
- });
- this.isShow = false;
- });
- },
- this.duration);
- }
- componentWillUnmount() {
- this.timer && clearTimeout(this.timer);
- }
- render() {
- let top;
- switch (this.props.position) {
- case 'top':
- top = 160;
- break;
- case 'center':
- top = height / 2;
- break;
- case 'bottom':
- top = height - 160;
- break;
- }
- let view = this.state.isShow ? "none" > this.state.opacityValue
- }]
- } > {
- this.state.text
- }
- : null;
- return view;
- }
- }
- const styles = StyleSheet.create({
- container: {
- position: 'absolute',
- left: 0,
- right: 0,
- alignItems: 'center',
- },
- content: {
- backgroundColor: 'black',
- opacity: OPACITY,
- borderRadius: 5,
- padding: 10,
- },
- text: {
- color: 'white'
- },
- })
如何使用:
- "toast" / >
- //省略...
- {
- this.refs.toast.show('你点击了忘记密码!', 3000);
- }
- } > 忘记密码?
- //省略...
在很多应用开发中都会涉及到获取手机验证码的场景,例如登录或者注册获取验证码。如下图:
那么按照自定义组件的流程,先添加构造函数,并定义必须的一些字段 (相关属性),并完成初始化:
- static propTypes = {
- style: PropTypes.object,
- //style属性
- textStyle: Text.propTypes.style,
- //文本文字
- onClick: PropTypes.func,
- //点击事件
- disableColor: PropTypes.string,
- //倒计时过程中颜色
- timerTitle: PropTypes.string,
- //倒计时文本
- enable: React.PropTypes.oneOfType([React.PropTypes.bool, React.PropTypes.number])
- };
2,构造函数:
- constructor(props) {super(props)this.state = {
- timerCount:this.props.timerCount ||60,//默认倒计时时间timerTitle:this.props.timerTitle ||'获取验证码',
- counting:false,
- selfEnable:true,
- };this.shouldStartCountting =this.shouldStartCountting.bind(this)this.countDownAction =this.countDownAction.bind(this)
- }
3,添加绘制界面代码:
- render() {
- const {
- onClick,
- style,
- textStyle,
- disableColor
- } = this.props;
- const {
- counting,
- timerTitle,
- selfEnable
- } = this.state;
- return (1 : 0.8
- }
- onPress = { () = >{
- if (!counting && selfEnable) {
- this.setState({
- selfEnable: false
- });
- this.shouldStartCountting(true);
- };
- }
- } >
- fontSize: 12
- },
- textStyle,
- {
- color: ((!counting && selfEnable) ? textStyle.color: disableColor || 'gray')
- }]
- } > {
- timerTitle
- }
- )
- }
4,添加逻辑代码:
- shouldStartCountting(shouldStart) {
- if (this.state.counting) {
- return
- }
- if (shouldStart) {
- this.countDownAction() this.setState({
- counting: true,
- selfEnable: false
- })
- } else {
- this.setState({
- selfEnable: true
- })
- }
- }
- //倒计时逻辑
- countDownAction() {
- const codeTime = this.state.timerCount;
- this.interval = setInterval(() = >{
- const timer = this.state.timerCount - 1
- if (timer === 0) {
- this.interval && clearInterval(this.interval);
- this.setState({
- timerCount: codeTime,
- timerTitle: this.props.timerTitle || '获取验证码',
- counting: false,
- selfEnable: true
- })
- } else {
- this.setState({
- timerCount: timer,
- timerTitle: `重新获取 ($ {
- timer
- }
- s)`,
- })
- }
- },
- 1000)
- }
说明: shouldStartCountting:回调函数,接受一个 Bool 类型的参数 1,shouldStartCountting(true),开始倒计时,倒计时结束时自动恢复初始状态 2,shouldStartCountting(false), 按钮的 selfEnable 会立即被置为 true 所以,获取验证码的完整代码如下:
- /**
- * Sample React Native App
- * https://github.com/facebook/react-native
- * @flow
- */
- import React,
- {
- Component,
- PropTypes
- }
- from 'react';
- import {
- Text,
- StyleSheet,
- View,
- TouchableOpacity,
- }
- from 'react-native';
- var Dimensions = require('Dimensions');
- var screenWidth = Dimensions.get('window').width;
- export
- default class TimerButton extends Component {
- constructor(props) {
- super(props) this.state = {
- timerCount: this.props.timerCount || 60,
- timerTitle: this.props.timerTitle || '获取验证码',
- counting: false,
- selfEnable: true,
- };
- this.shouldStartCountting = this.shouldStartCountting.bind(this) this.countDownAction = this.countDownAction.bind(this)
- }
- static propTypes = {
- style: PropTypes.object,
- textStyle: Text.propTypes.style,
- onClick: PropTypes.func,
- disableColor: PropTypes.string,
- timerTitle: PropTypes.string,
- enable: React.PropTypes.oneOfType([React.PropTypes.bool, React.PropTypes.number])
- };
- countDownAction() {
- const codeTime = this.state.timerCount;
- this.interval = setInterval(() = >{
- const timer = this.state.timerCount - 1
- if (timer === 0) {
- this.interval && clearInterval(this.interval);
- this.setState({
- timerCount: codeTime,
- timerTitle: this.props.timerTitle || '获取验证码',
- counting: false,
- selfEnable: true
- })
- } else {
- this.setState({
- timerCount: timer,
- timerTitle: `重新获取 ($ {
- timer
- }
- s)`,
- })
- }
- },
- 1000)
- }
- shouldStartCountting(shouldStart) {
- if (this.state.counting) {
- return
- }
- if (shouldStart) {
- this.countDownAction() this.setState({
- counting: true,
- selfEnable: false
- })
- } else {
- this.setState({
- selfEnable: true
- })
- }
- }
- componentWillUnmount() {
- clearInterval(this.interval)
- }
- render() {
- const {
- onClick,
- style,
- textStyle,
- disableColor
- } = this.props;
- const {
- counting,
- timerTitle,
- selfEnable
- } = this.state;
- return (1 : 0.8
- }
- onPress = { () = >{
- if (!counting && selfEnable) {
- this.setState({
- selfEnable: false
- });
- this.shouldStartCountting(true);
- };
- }
- } >
- 12
- },
- textStyle,
- {
- color: ((!counting && selfEnable) ? textStyle.color: disableColor || 'gray')
- }]
- } > {
- timerTitle
- }
- )
- }
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- marginTop: 20
- },
- styleCodeView: {
- height: 28,
- width: screenWidth * 0.22,
- borderColor: '#dc1466',
- borderWidth: 1,
- borderRadius: 5,
- justifyContent: 'center',
- alignItems: 'center',
- },
- styleTextCode: {
- fontSize: 12,
- color: '#dc1466',
- textAlign: 'center',
- },
- });
- import TimerButton from './TimerButton'
- var Dimensions = require('Dimensions');
- var screenWidth = Dimensions.get('window').width;
- //省略...
- 0.2,
- marginRight: 10
- }
- }
- timerCount = {
- 60
- }
- textStyle = {
- {
- color: '#dc1466'
- }
- }
- onclick = { (start) = >{}
- }
- />/
来源: http://blog.csdn.net/xiangzhihong8/article/details/73555973