ReactNative學(xué)習(xí)之自定義Button

不管是Android還是ios涤久,Button控件都在這兩個(gè)原生開發(fā)中都已經(jīng)被封裝好了铸鹰,我們可以直接使用年缎。但是在RN中并沒有直接提供這種組件給我們,而是給我們提供了一個(gè)可點(diǎn)擊的組件:Touchable系列(如TouchableOpacity, TouchableHighlight等)铃慷。那么今天我們就一起來學(xué)習(xí)封裝屬于我們自己的Button单芜。看一下我們的效果圖

CustomButton.gif
CustomButton_Android.gif

上面的效果圖中有三個(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í),請各位朋友不吝告知八蚕睢蔗蹋!

完整代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市囱淋,隨后出現(xiàn)的幾起案子猪杭,更是在濱河造成了極大的恐慌,老刑警劉巖妥衣,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皂吮,死亡現(xiàn)場離奇詭異,居然都是意外死亡称鳞,警方通過查閱死者的電腦和手機(jī)涮较,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門稠鼻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冈止,“玉大人,你說我怎么就攤上這事候齿∥醣” “怎么了闺属?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長周霉。 經(jīng)常有香客問我掂器,道長,這世上最難降的妖魔是什么俱箱? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任国瓮,我火速辦了婚禮,結(jié)果婚禮上狞谱,老公的妹妹穿的比我還像新娘乃摹。我一直安慰自己,他們只是感情好跟衅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布孵睬。 她就那樣靜靜地躺著,像睡著了一般伶跷。 火紅的嫁衣襯著肌膚如雪掰读。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天叭莫,我揣著相機(jī)與錄音蹈集,去河邊找鬼。 笑死雇初,一個(gè)胖子當(dāng)著我的面吹牛雾狈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抵皱,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼善榛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呻畸?” 一聲冷哼從身側(cè)響起移盆,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伤为,沒想到半個(gè)月后咒循,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绞愚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年叙甸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片位衩。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裆蒸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糖驴,到底是詐尸還是另有隱情僚祷,我是刑警寧澤佛致,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站辙谜,受9級(jí)特大地震影響俺榆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜装哆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一罐脊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜕琴,春花似錦爹殊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至号醉,卻和暖如春反症,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背畔派。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國打工铅碍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人线椰。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓胞谈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親憨愉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烦绳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 6,365評(píng)論 0 17
  • View 個(gè)人感覺View就類似于html中的div標(biāo)簽配紫,支持flexbox布局径密。 一個(gè)簡單的練習(xí),類似攜程的格子...
    45b645c5912e閱讀 1,175評(píng)論 0 0
  • 一. 簡介 React Native沒有像Web開發(fā)那樣給元素綁定click事件,Text組件有onPress事件...
    飛奔的小馬閱讀 1,391評(píng)論 0 0
  • 前言 本文有配套視頻躺孝,可以酌情觀看享扔。 文中內(nèi)容因各人理解不同,可能會(huì)有所偏差植袍,歡迎朋友們聯(lián)系我惧眠。 文中所有內(nèi)容僅供...
    珍此良辰閱讀 1,500評(píng)論 13 7
  • (為了你,這座古鎮(zhèn)已等待了千年) 踏進(jìn)鳳凰的那一刻于个,感覺是要冷死我了氛魁,只能說呆在湛江久了對(duì)氣溫會(huì)產(chǎn)生一種鈍覺。當(dāng)然...
    森陌ht閱讀 145評(píng)論 0 0