最近在學(xué)習(xí)React Native,學(xué)習(xí)實(shí)現(xiàn)過程中遇到的一些問題和心得蚊锹,先總結(jié)一部分出來寝优,與大家一起學(xué)習(xí)進(jìn)步。
大部分簡(jiǎn)單的功能實(shí)現(xiàn)官方文檔的說明都很清楚枫耳,我這里主要說一下我在開發(fā)過程中遇到的一些棘手的問題和解決辦法
1.布局和視覺樣式部分
a.RN中如何實(shí)現(xiàn)FrameLayout效果
如果要在RN中實(shí)現(xiàn)類似Android中的FrameLayout效果乏矾,需要對(duì)view的style設(shè)置 positon: 'absolute' ,以及一些方向?qū)傩?/p>
goods_left_label_style: {
position: 'absolute',//相對(duì)父元素進(jìn)行絕對(duì)定位
left: 0,
top: 0,
right:0迁杨,
bottom:0 //后面四個(gè)根據(jù)需要設(shè)置
},
b.等比例權(quán)重布局
要進(jìn)行等比例權(quán)重布局需要使用一個(gè)重要的屬性钻心,flexDirection,該屬性用于指定主軸的方向铅协。即指定子view的布局方向捷沸。可以設(shè)置兩個(gè)值分別是:row和column狐史。感覺上類似于orientation痒给。接著在子布局中設(shè)置flex屬性就是view的權(quán)重了说墨,類似于android中的weight。
除了flexDirection之外還有幾個(gè)很重要的屬性苍柏,下面說明一下他們的使用方法:
justifyContent和alignItems,這兩個(gè)屬性是相對(duì)的尼斧,第一個(gè)是設(shè)置子View的水平方向布局,第二個(gè)是設(shè)置VIew的豎直方向布局试吁,他們的取值有相同也有不同棺棵。這兩個(gè)屬性都可以取三個(gè)值,分別是flex-start,flex-end,center,意思分別是頂部對(duì)齊熄捍,底部對(duì)齊烛恤,居中對(duì)齊。
接著說他們不同的部分余耽,justifyContent還有一個(gè)stretch屬性缚柏,意思是在豎直方向上填充整個(gè)父布局;alignItems有兩個(gè)分別是space-between和spage-around屬性碟贾,這兩個(gè)很特別在android上是沒有的船惨,space-between意思是第一個(gè)子組件位于父容器左端,最后一個(gè)子組件位于父容器最右端缕陕。然后平均分配在父容器水平方向上粱锐。space-around指所有子組件平均分配在父容器的水平方向上,左右都有留空隙扛邑。
以上的兩個(gè)屬性都是父布局管理子布局的屬性怜浅,還有一個(gè)屬性是alignSelf,他是用來單獨(dú)設(shè)置組件豎直方向的樣式蔬崩,與alignItem類似恶座,只是一個(gè)設(shè)置父一個(gè)設(shè)置子。
flexWrap用于設(shè)置子view是否可以換行沥阳,有兩個(gè)屬性可設(shè)置nowrap和wrap跨琳。nowrap:即使空間不夠也不換行。wrap:空間不夠的話自動(dòng)換行桐罕。
c.View中設(shè)置Style
多個(gè)style可以組合起來使用脉让。比如:
<Text style={[styles.bigblue, styles.red]}>red, then bigblue</Text>
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
因?yàn)楹髮懙膔ed所以,里面的color會(huì)覆蓋掉之前bigblue的color功炮,但是其他的屬性仍然沿用bigblue中的溅潜。
d.點(diǎn)擊事件
在RN中的點(diǎn)擊事件似乎必須在需要點(diǎn)擊的View外部嵌套一個(gè)"Touchable"開頭的一系列組件,這些組件通過onPress屬性接受一個(gè)點(diǎn)擊事件的處理函數(shù)薪伏,在函數(shù)中處理相應(yīng)的點(diǎn)擊事件滚澜。看一下代碼:
<TouchableOpacity onPress = {this._onPressBack}>
<Image style = {styles.title_btn_style} source = {THUMB_URLS[0]} resizeMode = "contain"/>
</TouchableOpacity>
_onPressBack(){
AppModule.finishActivity()
}
e.顯示或隱藏view
RN感覺并沒有像Android那樣提供visible這樣的屬性嫁怀,可以直接通過設(shè)置visible來控制view的顯示设捐。如果要控制view的顯示的話借浊,需要在render view的時(shí)候設(shè)置相應(yīng)的顯示隱藏方法。再通過state狀態(tài)值的改變來在交互過程中進(jìn)行更新萝招÷旖铮看下代碼:
render() {
return (
<View style = {{flex:1}}>
<View style = {styles.occupy} />
{this._getPersonalActivityRemindView()}
{this._getPullToRefreshListView()}
</View>
);
}
_getPersonalActivityRemindView() {
if (this.state.personalActivityRemind !== '') {
return (
<View>
<View style = {{padding: 10,alignItems: 'center',backgroundColor: '#FFFFFF'}}>
<Text style = {{color: '#333333'}}>
</Text>
<Text style = {{color: '#e31436'}}>
{this.state.personalActivityRemind}
</Text>
</View>
<View style = {styles.occupy} />
</View>
)
}
}
2.針對(duì)新手關(guān)于ES5和ES6的問題
網(wǎng)上關(guān)于RN的文章越來越多了,但是隨著ES6的普及即寒,網(wǎng)上大部分的代碼都是有的用ES5有的用ES6橡淆,還有兩個(gè)混著用的召噩。我在一開始不是很熟悉看得時(shí)候很容易錯(cuò)亂母赵,推薦在看官方文檔的時(shí)候可以順便看一眼這篇文章,我涉及到的大部分ES的問題這里都說到了具滴。
react-native-的es5-es6寫法對(duì)照表凹嘲,而且從0.18開始,RN的新項(xiàng)目默認(rèn)模板已經(jīng)全面轉(zhuǎn)向ES6了构韵。
3.使用ref可以在外部使用view的引用
使用ref可以在某些view不方便通過props或state更新的時(shí)候使用周蹭,主要是在render外面使用view的引用。
render: function() {
return <TextInput ref={(c) => this._input = c} />;
},
componentDidMount: function() {
this._input.focus();
},
上面的代碼通過制定引用疲恢,在外部的componentDidMount方法中便可食用此view的引用凶朗。ref同樣可以使用字符串,例如:ref = "listview"显拳,這種方式在外部使用的時(shí)候需要這樣調(diào)用:this.refs.listview棚愤。剩余細(xì)節(jié)的使用方法可以參考文章:Refs to Components。
4.ListView使用遇到的一些問題
a.RN在0.24.1版本之后ListView在使用過程中會(huì)出現(xiàn)empty section headers 的警告杂数。
Warning: In next release empty section headers will be rendered. In this release you can use 'enableEmptySections' flag to render empty section headers.
如果需要去除這個(gè)警告的話需要在listview中添加enableEmptySections = {true}
b.RN官方的ListView中本身提供了上拉分頁刷新宛畦,在ListView組件中使用onEndReach()方法可以很簡(jiǎn)單的實(shí)現(xiàn)上拉分頁加載效果。同時(shí)揍移,針對(duì)下拉刷新次和,RN官方的ListView也提供了RefreshControl來管理,可以在ListView中直接使用RefreshControl來實(shí)現(xiàn)下拉刷新效果那伐。
<ListView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}//刷新方法需要自己實(shí)現(xiàn)
onEndReached = {this._onEndReached}//滾動(dòng)到底是加載數(shù)據(jù)的方法需自己實(shí)現(xiàn)
onEndReachedThreshold = {40}//這個(gè)參數(shù)表示距離底部多少時(shí)出發(fā)onEndReached
/>
}
...
5.自定義view
先總結(jié)一下在原有組件之上定義自己的view踏施。目前還不會(huì)完全自定義view的實(shí)現(xiàn)。
1.自定義自己需要的屬性罕邀,類似于Android中的attrs读规,首先需要聲明屬于自己的PropTypes以及他們的類型,例如:
propTypes: {
customStyles: React.PropTypes.object,
initialListSize: React.PropTypes.number,
firstLoader: React.PropTypes.bool,
paginationFetchingView: React.PropTypes.func,
onFetch: React.PropTypes.func,
}
這樣聲明相當(dāng)于設(shè)置一個(gè)驗(yàn)證器燃少,當(dāng)向 props 傳入無效數(shù)據(jù)時(shí)束亏,JavaScript 控制臺(tái)會(huì)拋出警告。
2.通過getDefaultProps方法可以給自定義的屬性設(shè)置默認(rèn)值
getDefaultProps() {
return {
customStyles: {},
initialListSize: 10,
firstLoader: true,
pagination: true,
onFetch(page, callback, options) { callback([]); },
}
3.當(dāng)某個(gè)屬性沒有被重新定義的時(shí)候阵具,作為自定義的view碍遍,最好可以定義一個(gè)通用的方法定铜,即默認(rèn)流程,來防止出現(xiàn)一些問題
renderSeparator() {
if (this.props.renderSeparator) {
return this.props.renderSeparator();
}
return (
<View style={[this.defaultStyles.separator, this.props.customStyles.separator]} />
);
},
4.通過getInitialState方法設(shè)置初始換的狀態(tài)值怕敬,通過狀態(tài)值的改變可以更新view的顯示效果揣炕,例如更新listview的數(shù)據(jù),讓listview加載更多等东跪。
getInitialState() {
this._setPage(1);
this._setRows([]);
return {
dataSource: ds.cloneWithRows(this._getRows()),
isRefreshing: false,
paginationStatus: 'firstLoad',
};
},
5.setNativeProps方法
如果你通過React.createClass方法自定義了一個(gè)組件畸陡,直接給它設(shè)置樣式prop是不會(huì)生效的,你得把樣式props層層向下傳遞給子組件虽填,直到子組件是一個(gè)能夠直接定義樣式的原生組件丁恭。同理,我們也需要把setNativeProps傳遞給由原生組件封裝的子組件斋日。
setNativeProps(props) {
this.refs.listview.setNativeProps(props);
},
render() {
return (
<ListView
ref="listview"
dataSource={this.state.dataSource}
renderRow={this.props.rowView}
{...this.props}
style={this.props.style}
/>
);
},
其中View中設(shè)置的{...this.props}這句話也很重要牲览,我的理解是所繼承的原生view屬性太多,通過這句話復(fù)用父類的方法恶守。比如你不想自己處理點(diǎn)擊拖動(dòng)效果第献,就直接繼承過來.