1. 程式人生 > >React Native 自定義控制元件之驗證碼和Toast

React Native 自定義控制元件之驗證碼和Toast

React Native通過近兩年的迭代和維護,最新版本已經到了0.45.1,關於最新版本的介紹請檢視我之前的部落格:0.45新特性。話說回來,儘管迭代的挺快,但還是有很多坑,很多基礎的元件和API還是不完善。

今天給大家帶來的自定義小專題,其實對於React Native來說,自定義元件的過程更像是Android、iOS的組合控制元件。大體步驟有如下幾個步驟(不完全準確,但是方向大體準確):
1,定義建構函式constructor;
2,定義元件屬性propTypes;
3,繪製介面;
4,新增更新介面邏輯等

自定義Toast

在系統元件中,RN為我們提供了ToastAndroid元件,但是對於iOS好像並沒有直接提供,這時候我們就想到了自定義控制元件了。如下圖所示:
這裡寫圖片描述

我們之前講過Animated元件,這個元件可以實現漸變,縮放,旋轉等動畫效果,在這裡,我們可以用它來實現Toast的功能。比如,顯示兩秒後消失,為了對顯示的位置進行設定,我們還可以設定顯示的位置,所以繪製render的程式碼如下:

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 ? <View style={[styles.container,{top:top}]} pointerEvents="none" > <Animated.View style={[styles.content,{opacity:this
.state.opacityValue}]} > <Text style={styles.text}>{this.state.text}</Text> </Animated.View> </View> : null; return view; }

顯示時長控制方法:

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 ?
            <View
                style={[styles.container,{top:top}]}
                pointerEvents="none"
            >
                <Animated.View
                    style={[styles.content,{opacity:this.state.opacityValue}]}
                >
                    <Text style={styles.text}>{this.state.text}</Text>
                </Animated.View>
            </View> : 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 ref="toast"/>
 //省略...
 <Text style={styles.styleText} onPress={()=>{
                    this.refs.toast.show('你點選了忘記密碼!',3000);}}>
  忘記密碼?
 </Text>
 //省略...

獲取驗證碼

在很多應用開發中都會涉及到獲取手機驗證碼的場景,例如登入或者註冊獲取驗證碼。如下圖:
這裡寫圖片描述這裡寫圖片描述

那麼按照自定義元件的流程,先新增建構函式,並定義必須的一些欄位(相關屬性),並完成初始化:

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 (
            <TouchableOpacity activeOpacity={counting ? 1 : 0.8} onPress={() => {
                if (!counting &&selfEnable) {
                    this.setState({selfEnable: false});
                    this.shouldStartCountting(true);
                };
            }}>
                <View
                    style={styles.styleCodeView}>
                    <Text
                        style={[{fontSize: 12}, textStyle, {color: ((!counting && selfEnable) ? textStyle.color : disableColor || 'gray')}]}>{timerTitle}</Text>
                </View>
            </TouchableOpacity>
        )
    }

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 (
            <TouchableOpacity activeOpacity={counting ? 1 : 0.8} onPress={() => {
                if (!counting &&selfEnable) {
                    this.setState({selfEnable: false});
                    this.shouldStartCountting(true);
                };
            }}>
                <View
                    style={styles.styleCodeView}>
                    <Text
                        style={[{fontSize: 12}, textStyle, {color: ((!counting && selfEnable) ? textStyle.color : disableColor || 'gray')}]}>{timerTitle}</Text>
                </View>
            </TouchableOpacity>
        )
    }
}

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;

//省略...
<TimerButton
 style={{width: screenWidth*0.2,marginRight: 10}}
 timerCount={60}
 textStyle={{color: '#dc1466'}}
 onclick={(start)=>{
 }}/>

相關推薦

React Native 定義控制元件驗證Toast

React Native通過近兩年的迭代和維護,最新版本已經到了0.45.1,關於最新版本的介紹請檢視我之前的部落格:0.45新特性。話說回來,儘管迭代的挺快,但還是有很多坑,很多基礎的元件和API還是不完善。 今天給大家帶來的自定義小專題,其實對於React

react-native定義控制元件怎麼實現螢幕寬度的80%

原來我們講過在定義PixelRatio後可以獲取螢幕的寬度,程式碼如下: var width = Dimensions.get(‘window’).width; 然後在類CSS樣式中採用:widt

定義控制元件側滑關閉 Activity 控制元件

隔壁 iOS 的小夥伴有一個功能就是左手向右手一個慢動作,輕輕一劃就可以關閉介面,這種操作感覺還是很絲滑的,而且這還是 iOS 系統自帶的功能,由於 Android 手機早期是有 back 鍵,home 鍵 和選單鍵(現在大部分手機都只保留一個鍵了),所以 Android 是沒有這個功能的。現在

定義控制元件下載控制元件1(DownloadView1)

前段時間在乾貨集中營看到了兩個炫酷的下載按鈕:       可惜是隔壁 iOS 的孩子,怎麼辦,我也好喜歡,emmm,某該,只能自己模仿著實現一下了。先從第一個入手(第二個波浪效果暫時還不會)。 1 準備動作 寫過幾次自定義控制元件

定義控制元件 PasswordEditText(密碼輸入框)

前兩天在掘金上看到了一個驗證碼輸入框,然後自己實現了一下,以前都是繼承的 View,這次繼承了 ViewGroup,也算是嘗試了一點不同的東西。先看看最終效果: 事實上就是用將輸入的密碼用幾個文字框來顯示而已,要打造這樣一個東西我剛開始也是一頭霧水,不急,直接寫不會,我們可以採取曲線救

定義控制元件 Gamepad (遊戲手柄)

這段時間自己在復刻一個小時候玩過的小遊戲——魔塔,在人物操控的時候剛開始用的感覺 low low 的上下左右四個方向鍵,後來受王者農藥啟發,決定採用現在很多遊戲中的那種遊戲手柄,網上也有例子,不過最近自己對自定義控制元件很感興趣,決定自己擼一個,最後實現的效果是這樣的: 看到這樣

定義控制元件 SubmitBotton (提交按鈕)

在 Android 中我覺得除了實現很多功能性很強的需求之外,最吸引我的就是各種炫酷的自定義控制元件,但是自定義控制元件這個東西沒有辦法用一種固定的模式來講解,因為自定義控制元件都是根據需求來定製的。同時這也說明只要程式猿牛逼,就沒有實現不了的功能。 之前有看到一個效果: Android

react-native定義原生元件

此文已由作者王翔授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 使用react-native的時候能夠看到不少函式呼叫式的元件,像LinkIOS用來呼起url請求  LinkIOS.openUrl('http://www.163.com'); ac

定義控制元件固定Tab

在開發中我們通常用到固定的Tab,Tab的個數是可以動態配置的,但是不支援滑動,每個Tab均分佈局並且之間被一個豎線分割開,Tab底部是一條分割線。看到如下效果如下,Tab佈局、線條顏色都支援高度制定。這個Tab的難點在於首先Tab個數不固定,其次Tab豎線左右兩端沒有隻有相鄰的兩個才有,而且粗

wpf定義控制元件依賴屬性

  在wpf開發過程中,總會用到格式各樣的控制元件,但是原生控制元件遠遠不能滿足實際開發的需要,這時候wpf強大之處就能體現出來了。根據實際需求自定義各種不同的控制元件滿足不同的業務需求。 首先說需求吧: 一:根據某個bool值,控制一個圓形控制元件顯示或者不顯示某種顏色。 分析: 一:需

Android定義控制元件區域性圖片放大鏡--BiggerView

零、前言: 本文的知識點一覽 1.自定義控制元件及自定義屬性的寫法,你也將對onMesure有更深的認識 2.關於bitmap的簡單處理,及canvas區域裁剪 3.本文會實現兩個自定義控制元件:FitImageView(圖片自適應)和BiggerView(放大鏡),前者為後者作為鋪墊。 4.最後會

定義控制元件輪播圖的實現

public class BannerView extends RelativeLayout { private boolean startAndclose; private List<String> images = new ArrayList

【我的Android進階旅】定義控制元件使用ViewPager實現可以預覽的畫廊效果,並且定義畫面切換的動畫效果的切換時間

我們來看下效果 在這裡,我們實現的是,一個ViewPager來顯示圖片列表。這裡一個頁面,ViewPage展示了前後的預覽,我們讓預覽頁進行Y軸的壓縮,並設定透明度為0.5f,所有我們看到gif最後,左右兩邊的圖片有點朦朧感。讓預覽頁和主頁面有主從感。我們用分

Android定義控制元件仿汽車家下拉重新整理

關於下拉重新整理的實現原理我在上篇文章Android自定義控制元件之仿美團下拉重新整理中已經詳細介紹過了,這篇文章主要介紹錶盤的動畫實現原理 汽車之家的下拉重新整理分為三個狀態: 第一個狀態為下拉重新整理狀態(pull to refresh),在這個狀

定義控制元件組合式控制元件 下拉選擇框

自定義控制元件之組合式控制元件 下拉選擇框 文章目錄 自定義控制元件之組合式控制元件 下拉選擇框 零 組合控制元件下載 一 自定義控制元件思路 二 MainActivity核心程式碼 三 activity_main.xml

定義控制元件二階貝塞爾曲線方法詳解

前言:先膜拜一下啟艦大神,本想自己寫一篇關於貝塞爾曲線的文章,但無奈此大神寫的太6了 ,所以直接轉載 相關文章:《Android自定義控制元件三部曲文章索引》: http://blog.csdn.net/harvic880925/article/details/50995268從

定義控制元件文字繪製

paint與文字設定相關的方法如下 paint.setStrokeWidth(5);//畫筆寬度 paint.setColor(Color.RED);//設定顏色 paint.setAntiAlias(true);//抗鋸齒功能 p

Winform----定義控制元件背景半透明遮罩載入控制元件

先貼執行效果圖,原始碼點選這裡下載 1.新建自定義控制元件 2.實現功能 namespace UserControlLib { [ToolboxBitmap(typeof(ZhLoading))] public partial class ZhLoad

Android定義控制元件《折線圖的繪製》

金融軟體裡的行情分時圖,這是我們最常見的折線圖,當然了,折線圖的用途並不僅僅侷限於此,像一般在一定區間內,為了更好的能顯示出幅度的變化,那麼用折線圖來展示無疑是最符合效果的,當然了,網上也有很多的第

Android定義控制元件實現滑動選擇開關

前言:今天我們仿照著Google給我們提供的Switch控制元件來進行一次模仿,自己動手打造一個可以換滑動圖片以及背景的圖片。 -----------------分割線--------------- 先看一下google提供的Switc控制元件: 其實用法很簡單就當普通的