不管是Android還是ios涤久,Button控件都在這兩個(gè)原生開發(fā)中都已經(jīng)被封裝好了铸鹰,我們可以直接使用年缎。但是在RN中并沒有直接提供這種組件給我們,而是給我們提供了一個(gè)可點(diǎn)擊的組件:Touchable系列(如TouchableOpacity, TouchableHighlight等)铃慷。那么今天我們就一起來學(xué)習(xí)封裝屬于我們自己的Button单芜。看一下我們的效果圖
上面的效果圖中有三個(gè)Button犁柜,若不封裝的話洲鸠,我們就肯定會(huì)寫很多重復(fù)代碼,這對(duì)于一個(gè)面向?qū)ο蟮某绦騿T來說肯定是不能接受的馋缅。好了扒腕,那我們就一起來實(shí)現(xiàn)封裝的代碼吧。若不熟悉Touchable系列組件的萤悴,可以先看看我之前寫的文章瘾腰。
實(shí)現(xiàn)步驟
-
step 1 先封裝一個(gè)可點(diǎn)擊的button
_renderTouchableHighlight(selectedColor, type,style) { return ( <TouchableHighlight underlayColor={selectedColor} onPress={this._onPress} style={[styles.container, type,style, this.state.disable && {backgroundColor: this.props.disableColor}]} disabled={this.state.disable} > <Text style={this.props.textStyle}>{this.props.text}</Text> </TouchableHighlight> ); } _renderTouchableOpacity(type,style) { return ( <TouchableOpacity onPress={this._onPress} style={[styles.container, type, style]} disabled={this.state.disable} > <Text style={this.props.textStyle}>{this.props.text}</Text> </TouchableOpacity> ); }
這里用兩個(gè)方法來渲染不同類型的button,其實(shí)它們的不同之處在于:當(dāng)Button被點(diǎn)擊的時(shí)候覆履,button需要呈現(xiàn)出什么樣的狀態(tài)來進(jìn)行視覺交互蹋盆。RN已經(jīng)給Opacity類型的button設(shè)置了selected狀態(tài),但我們?nèi)粜枰约憾xselected按鈕狀態(tài)的話硝全,就需要使用TouchableHighlight類型的栖雾。
方法中的selectedColor用來判斷使用者是選擇何種類型的button,若傳來了selectedColor伟众,那么就作為TouchableHighlight的underlayColor析藕。對(duì)于整個(gè)button長什么樣,由使用者去定制凳厢,不過我們可肯定的是账胧,button的文字肯定是居中的,所以設(shè)置了styles.container数初,代碼如下:
container: {
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden' //這個(gè)屬性定義溢出元素內(nèi)容區(qū)的內(nèi)容會(huì)如何處理,內(nèi)容會(huì)被修剪找爱,并且其余內(nèi)容是不可見的梗顺。
},
方法中第二個(gè)參數(shù)type是用來決定用戶需要什么樣的button泡孩,是實(shí)心,空心或者僅是text寺谤。
static _setDifferentButtonStyle(buttonColor, buttonRadius, buttonType, borderWidth) {
if (buttonType == "normal") {
return CustomButton._setDifferentStyle(buttonColor, buttonRadius, buttonColor);
} else if (buttonType == 'stroke') {
return CustomButton._setDifferentStyle('transparent', buttonRadius, buttonColor, borderWidth);
} else if (buttonType == 'text') {
return CustomButton._setDifferentStyle('transparent', 0, 'transparent');
}
}
static _setDifferentStyle(backgroundColor, borderRadius, borderColor, borderWidth) {
return {
backgroundColor: backgroundColor,
borderRadius: borderRadius,
borderColor: borderColor,
borderWidth: borderWidth
};
}
上面代碼中仑鸥,可以根據(jù)使用者傳過來的buttonType類型來返回對(duì)應(yīng)的button樣式;至于第三個(gè)參數(shù)style变屁,是使用者設(shè)置button時(shí)傳過來的具體的樣式眼俊,我們可以直接拿來用。
- step 2 傳遞點(diǎn)擊事件
Touchable系列中有個(gè)onPress方法粟关,這是用來處理點(diǎn)擊事件的疮胖。我們不可能把外面?zhèn)鬟^來的事件在這個(gè)類中去處理,而是需要使用者自己處理。那如何做了澎灸?也就是事件的傳遞了院塞,另外一種說法就是回調(diào)。在最上面代碼中性昭,有看到onPress={this._onPress}拦止,那么這個(gè)this._onPress到底是誰了?
_onPress() {
if (this.props.onPress) {
this.props.onPress();
}
}
從上面的代碼中可以看出糜颠,最終是調(diào)到傳過來的onPress方法汹族。不過我們?nèi)糁苯舆@樣調(diào)的話,肯定會(huì)報(bào)錯(cuò)其兴。為什么顶瞒?因?yàn)檫@個(gè)方法是我們自己定義的,但沒有像組件的生命周期方法一樣忌警,在一個(gè)組件被創(chuàng)建時(shí)就已經(jīng)被初始化了搁拙。所以,我們需要將我們自己定義的方法與初始時(shí)進(jìn)行綁定法绵。初始化操作我們一般放在構(gòu)造方法中進(jìn)行箕速。
constructor(props) {
super(props);
this._onPress = this._onPress.bind(this);
}
- step 3 防重復(fù)點(diǎn)擊
網(wǎng)絡(luò)請求數(shù)據(jù)一般是耗時(shí)操作,為了防止用戶多次點(diǎn)擊button去請求數(shù)據(jù)朋譬,我們還需要設(shè)置在做耗時(shí)操作時(shí)盐茎,不能讓button變得可點(diǎn)擊,并且給出視覺交互徙赢。那如何來實(shí)現(xiàn)了字柠?我們可以通過狀態(tài)的改變來決定是否可以點(diǎn)擊。有兩種實(shí)現(xiàn)方式:
1狡赐、對(duì)外提供兩個(gè)方法窑业,讓使用者通過拿到我們自定義button的實(shí)例來調(diào)用這個(gè)暴露出去的方法,從而達(dá)到點(diǎn)擊與不可點(diǎn)擊的切換
2枕屉、我們可以將某個(gè)改變點(diǎn)擊狀態(tài)的方法傳給使用者進(jìn)行回調(diào)常柄,讓使用者決定什么時(shí)候可改變button的點(diǎn)擊狀態(tài)。
第一種相當(dāng)來說比較簡單搀擂,我們來使用第二種方式西潘。
constructor(props) {
super(props);
this._onPress = this._onPress.bind(this);
this._enable = this._enable.bind(this);
this._disable = this._disable.bind(this);
this.state = {
disable: false
}
}
_onPress() {
if (this.props.onPress) {
this._disable();
this.props.onPress(this._enable);
}
}
_enable() {
this.setState({
disable: false
});
};
_disable() {
this.setState({
disable: true
});
};
我們通過一個(gè)狀態(tài)值來保存button的可點(diǎn)擊狀態(tài),在button被點(diǎn)擊時(shí)哨颂,馬上將這個(gè)button置為不可點(diǎn)擊喷市,至于什么時(shí)候可以點(diǎn)擊,我們將enable方法回調(diào)給了使用者威恼,由使用者決定品姓。如上面所說寝并,我們自定義的方法都必須先在構(gòu)造方法中進(jìn)行初始化。
- step 4 設(shè)置屬性類型和默認(rèn)值
我們自定義的屬性需要什么類型腹备,使用者并不知道食茎,所以我們需要聲明我們自定義屬性的類型,可以通過PropTypes馏谨,并且還可以強(qiáng)制用戶必須傳哪些屬性别渔。
//屬性類型
CustomButton.propTypes = {
text: PropTypes.string.isRequired,
textStyle: Text.propTypes.style,
buttonType: PropTypes.oneOf(['normal', 'stroke', 'text']).isRequired,
selectedColor: PropTypes.string,
onPress: PropTypes.func,
buttonColor:PropTypes.string,
buttonRadius:PropTypes.number,
borderWidth:PropTypes.number,
};
//屬性默認(rèn)值
CustomButton.defaultProps = {
borderWidth: 1
};
最后是整個(gè)類的渲染
render() {
//這里是將props中屬性進(jìn)行解構(gòu),es6語法惧互,可查看阮一峰的《ES6標(biāo)準(zhǔn)與入門》
let {selectedColor, buttonColor, buttonRadius, buttonType, borderWidth, style}=this.props;
let type = CustomButton._setDifferentButtonStyle(buttonColor, buttonRadius, buttonType, borderWidth);
if (selectedColor) {
{
return this._renderTouchableHighlight(selectedColor, type, style);
}
} else {
{
return this._renderTouchableOpacity(type, style);
}
}
}
-
step 5 進(jìn)行測試
<View style={styles.container}> <CustomButton text="確定" buttonColor="red" buttonRadius={20} buttonType="normal" textStyle={styles.textStyle} style={styles.customButton} selectedColor="green" disableColor="yellow" onPress={(callback)=> { setTimeout(()=> { callback(); }, 3000); }} /> <CustomButton text="確定" buttonColor="red" buttonRadius={20} buttonType="stroke" textStyle={styles.textStyle} style={styles.customButton} selectedColor="green" disableColor="yellow" onPress={(callback)=> { setTimeout(()=> { callback(); }, 3000); }} /> <CustomButton text="確定" buttonColor="red" buttonRadius={20} buttonType="text" textStyle={styles.textStyle} selectedColor="green" disableColor="yellow" style={{marginTop:20}} onPress={(callback)=> { setTimeout(()=> { callback(); }, 3000); }} /> </View>
好了哎媚,自定義button就封裝完了以及學(xué)習(xí)了自定義一個(gè)組件需要做哪些事。這里面稍微有一點(diǎn)難度的就是方法的傳遞進(jìn)行回調(diào)喊儡。在java中是不允許方法作為參數(shù)傳遞的拨与。不過,在java中不能干的事艾猜,在js中可以干是非常常見的买喧。我們今天做的button主要是文字,其實(shí)還可以對(duì)其進(jìn)行拓展匆赃,那就是這個(gè)button為image時(shí)淤毛,那個(gè)比較簡單,有興趣的朋友可以進(jìn)一步進(jìn)行封裝算柳。
本人目前對(duì)于RN也還是處于學(xué)習(xí)的階段低淡,若在寫文章時(shí)出現(xiàn)了錯(cuò)誤或者代碼可以優(yōu)化時(shí),請各位朋友不吝告知八蚕睢蔗蹋!