ReactNative學習之自定義Button

不管是Android還是ios,Button控件都在這兩個原生開發中都已經被封裝好了,我們可以直接使用。但是在RN中并沒有直接提供這種組件給我們,而是給我們提供了一個可點擊的組件:Touchable系列(如TouchableOpacity, TouchableHighlight等)。那么今天我們就一起來學習封裝屬于我們自己的Button。看一下我們的效果圖

CustomButton.gif
CustomButton_Android.gif

上面的效果圖中有三個Button,若不封裝的話,我們就肯定會寫很多重復代碼,這對于一個面向對象的程序員來說肯定是不能接受的。好了,那我們就一起來實現封裝的代碼吧。若不熟悉Touchable系列組件的,可以先看看我之前寫的文章。

實現步驟

  • step 1 先封裝一個可點擊的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>
          );
      }
    

這里用兩個方法來渲染不同類型的button,其實它們的不同之處在于:當Button被點擊的時候,button需要呈現出什么樣的狀態來進行視覺交互。RN已經給Opacity類型的button設置了selected狀態,但我們若需要自己定義selected按鈕狀態的話,就需要使用TouchableHighlight類型的。

方法中的selectedColor用來判斷使用者是選擇何種類型的button,若傳來了selectedColor,那么就作為TouchableHighlight的underlayColor。對于整個button長什么樣,由使用者去定制,不過我們可肯定的是,button的文字肯定是居中的,所以設置了styles.container,代碼如下:

container: {
    justifyContent: 'center',
    alignItems: 'center',
    overflow: 'hidden'  //這個屬性定義溢出元素內容區的內容會如何處理,內容會被修剪,并且其余內容是不可見的。
},

方法中第二個參數type是用來決定用戶需要什么樣的button,是實心,空心或者僅是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
    };
}

上面代碼中,可以根據使用者傳過來的buttonType類型來返回對應的button樣式;至于第三個參數style,是使用者設置button時傳過來的具體的樣式,我們可以直接拿來用。

  • step 2 傳遞點擊事件

Touchable系列中有個onPress方法,這是用來處理點擊事件的。我們不可能把外面傳過來的事件在這個類中去處理,而是需要使用者自己處理。那如何做了?也就是事件的傳遞了,另外一種說法就是回調。在最上面代碼中,有看到onPress={this._onPress},那么這個this._onPress到底是誰了?

_onPress() {
    if (this.props.onPress) {
        
        this.props.onPress();
    }
}

從上面的代碼中可以看出,最終是調到傳過來的onPress方法。不過我們若直接這樣調的話,肯定會報錯。為什么?因為這個方法是我們自己定義的,但沒有像組件的生命周期方法一樣,在一個組件被創建時就已經被初始化了。所以,我們需要將我們自己定義的方法與初始時進行綁定。初始化操作我們一般放在構造方法中進行。

constructor(props) {
    super(props);
    this._onPress = this._onPress.bind(this);
}
  • step 3 防重復點擊

網絡請求數據一般是耗時操作,為了防止用戶多次點擊button去請求數據,我們還需要設置在做耗時操作時,不能讓button變得可點擊,并且給出視覺交互。那如何來實現了?我們可以通過狀態的改變來決定是否可以點擊。有兩種實現方式:

1、對外提供兩個方法,讓使用者通過拿到我們自定義button的實例來調用這個暴露出去的方法,從而達到點擊與不可點擊的切換

2、我們可以將某個改變點擊狀態的方法傳給使用者進行回調,讓使用者決定什么時候可改變button的點擊狀態。

第一種相當來說比較簡單,我們來使用第二種方式。

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
    });
};

我們通過一個狀態值來保存button的可點擊狀態,在button被點擊時,馬上將這個button置為不可點擊,至于什么時候可以點擊,我們將enable方法回調給了使用者,由使用者決定。如上面所說,我們自定義的方法都必須先在構造方法中進行初始化。

  • step 4 設置屬性類型和默認值

我們自定義的屬性需要什么類型,使用者并不知道,所以我們需要聲明我們自定義屬性的類型,可以通過PropTypes,并且還可以強制用戶必須傳哪些屬性。

//屬性類型
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,
};

//屬性默認值
CustomButton.defaultProps = {

    borderWidth: 1
};

最后是整個類的渲染

render() {
    
    //這里是將props中屬性進行解構,es6語法,可查看阮一峰的《ES6標準與入門》
    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 進行測試

      <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就封裝完了以及學習了自定義一個組件需要做哪些事。這里面稍微有一點難度的就是方法的傳遞進行回調。在java中是不允許方法作為參數傳遞的。不過,在java中不能干的事,在js中可以干是非常常見的。我們今天做的button主要是文字,其實還可以對其進行拓展,那就是這個button為image時,那個比較簡單,有興趣的朋友可以進一步進行封裝。

本人目前對于RN也還是處于學習的階段,若在寫文章時出現了錯誤或者代碼可以優化時,請各位朋友不吝告知啊!

完整代碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,497評論 0 17
  • View 個人感覺View就類似于html中的div標簽,支持flexbox布局。 一個簡單的練習,類似攜程的格子...
    45b645c5912e閱讀 1,198評論 0 0
  • 一. 簡介 React Native沒有像Web開發那樣給元素綁定click事件,Text組件有onPress事件...
    飛奔的小馬閱讀 1,435評論 0 0
  • 前言 本文有配套視頻,可以酌情觀看。 文中內容因各人理解不同,可能會有所偏差,歡迎朋友們聯系我。 文中所有內容僅供...
    珍此良辰閱讀 1,519評論 13 7
  • (為了你,這座古鎮已等待了千年) 踏進鳳凰的那一刻,感覺是要冷死我了,只能說呆在湛江久了對氣溫會產生一種鈍覺。當然...
    森陌ht閱讀 162評論 0 0