前言
學(xué)習(xí)本系列內(nèi)容需要具備一定 HTML 開發(fā)基礎(chǔ),沒有基礎(chǔ)的朋友可以先轉(zhuǎn)至 HTML快速入門(一) 學(xué)習(xí)
本人接觸 React Native 時(shí)間并不是特別長窑业,所以對(duì)其中的內(nèi)容和性質(zhì)了解可能會(huì)有所偏差智什,在學(xué)習(xí)中如果有錯(cuò)會(huì)及時(shí)修改內(nèi)容持灰,也歡迎萬能的朋友們批評(píng)指出,謝謝
文章第一版出自簡書怎燥,如果出現(xiàn)圖片或頁面顯示問題瘫筐,煩請(qǐng)轉(zhuǎn)至 簡書 查看 也希望喜歡的朋友可以點(diǎn)贊,謝謝
ScrollView組件介紹與簡單使用
-
React Native中的
ScrollView
的組件除了包裝滾動(dòng)平臺(tái)铐姚,還集成了觸摸鎖定的響應(yīng)者
系統(tǒng)策肝,使用的時(shí)候有幾點(diǎn)需要注意- ScrollView 必須有一個(gè)確定的高度才能正常工作,對(duì)于
ScrollView
來說,它就是將一些不確定高度的子組件裝進(jìn)確定高度的容器 - 初始化的2中方式
- 不要給
ScrollView
中不要加 [flex:1] - 直接給該
ScrollView
設(shè)置高度(不建議)隐绵,因?yàn)樗鼤?huì)根據(jù)內(nèi)部組件自動(dòng)延伸自己的尺寸到合適的大小
- 不要給
- ScrollView 內(nèi)部的其它響應(yīng)者沒辦法阻止 ScrollView 本身成為響應(yīng)者(也就是說之众,ScrollView 響應(yīng)的優(yōu)先級(jí)比內(nèi)部組件高,且內(nèi)部組件沒辦法改變優(yōu)先級(jí))
- ScrollView 必須有一個(gè)確定的高度才能正常工作,對(duì)于
-
那么就先來看看怎么創(chuàng)建基本的
ScrollView
- 視圖部分
// 視圖 var CustomScrollView = React.createClass({ render(){ return( <ScrollView style={styles.mainStyle}> {this.renderItem()} </ScrollView> ); }, renderItem() { // 數(shù)組 var itemAry = []; // 顏色數(shù)組 var colorAry = ['gray', 'green', 'blue', 'yellow', 'black', 'orange']; // 遍歷 for (var i = 0; i<colorAry.length; i++) { itemAry.push( <View key={i} style={[styles.itemStyle, {backgroundColor: colorAry[i]}]}></View> ); } return itemAry; } });
- 樣式部分
// 樣式 var styles = StyleSheet.create({ scrollViewStyle: { // 背景色 backgroundColor:'red' }, itemStyle: { // 尺寸 width:1000, height:200 }, });
效果:
- 視圖部分
ScrollView 中常用的屬性
下面經(jīng)常使用和比較難理解的屬性會(huì)有示例代碼或效果圖
contentContainerStyle:這些樣式會(huì)引用到一個(gè)內(nèi)層的內(nèi)容容器上依许,所有的子視圖都會(huì)包裹在內(nèi)容容器內(nèi)
-
horizontal:當(dāng)此屬性為true的時(shí)候棺禾,所有的的子視圖會(huì)在水平方向上排成一行,而不是默認(rèn)的在垂直方向上排成一列峭跳。默認(rèn)值為false
<ScrollView style={styles.scrollViewStyle} horizontal={true} > {this.renderItem()} </ScrollView>
效果:
-
keyboardDismissMode:用戶拖拽滾動(dòng)視圖的時(shí)候膘婶,是否要隱藏軟鍵盤缺前。
- none(默認(rèn)值),拖拽時(shí)不隱藏軟鍵盤
- on-drag 當(dāng)拖拽開始的時(shí)候隱藏軟鍵盤
- interactive 軟鍵盤伴隨拖拽操作同步地消失悬襟,并且如果往上滑動(dòng)會(huì)恢復(fù)鍵盤衅码。安卓設(shè)備上不支持這個(gè)選項(xiàng),會(huì)表現(xiàn)的和none一樣脊岳。
keyboardShouldPersistTaps:當(dāng)此屬性為false的時(shí)候逝段,在軟鍵盤激活之后,點(diǎn)擊焦點(diǎn)文本輸入框以外的地方惹恃,鍵盤就會(huì)隱藏。如果為true参淹,滾動(dòng)視圖不會(huì)響應(yīng)點(diǎn)擊操作浙值,并且鍵盤不會(huì)自動(dòng)消失。默認(rèn)值為false
refreshControl:指定RefreshControl組件筐付,用于為ScrollView提供下拉刷新功能
-
removeClippedSubviews:(實(shí)驗(yàn)特性)當(dāng)此屬性為true時(shí)瓦戚,屏幕之外的子視圖(子視圖的overflow樣式需要設(shè)為hidden)會(huì)被移除。這個(gè)可以提升大列表的滾動(dòng)性能印衔。默認(rèn)值為true
var styles = StyleSheet.create({ child: { ... // 因?yàn)槟J(rèn)為true当编,所以我們只需要在子視圖將下面樣式設(shè)為hidden就可以了 overflow: 'hidden' }, });
-
showsHorizontalScrollIndicator:當(dāng)此屬性為true的時(shí)候,顯示一個(gè)水平方向的滾動(dòng)條
<ScrollView style={styles.scrollViewStyle} horizontal={true} showsHorizontalScrollIndicator={true} > {this.renderItem()} </ScrollView>
效果:
-
showsVerticalScrollIndicator:當(dāng)此屬性為true的時(shí)候揍拆,顯示一個(gè)垂直方向的滾動(dòng)條
<ScrollView style={styles.scrollViewStyle} showsVerticalScrollIndicator={true} > {this.renderItem()} </ScrollView>
效果:
endFillColor:有時(shí)候滾動(dòng)視圖會(huì)占據(jù)比實(shí)際內(nèi)容更多的空間。這種情況下可以使用此屬性筒狠,指定以某種顏色來填充多余的空間,以避免設(shè)置背景和創(chuàng)建不必要的繪制開銷灶伊。一般情況下并不需要這種高級(jí)優(yōu)化技巧
-
alwaysBounceHorizontal:當(dāng)此屬性為true時(shí)聘萨,水平方向即使內(nèi)容比滾動(dòng)視圖本身還要小,也可以彈性地拉動(dòng)一截儡循。當(dāng)horizontal={true}時(shí)(默認(rèn)值為true)否則為false
<ScrollView style={styles.scrollViewStyle} horizontal={true} alwaysBounceHorizontal={true} > {this.renderItem()} </ScrollView>
效果:
-
alwaysBounceVertical:當(dāng)此屬性為true時(shí)检激,垂直方向即使內(nèi)容比滾動(dòng)視圖本身還要小叔收,也可以彈性地拉動(dòng)一截。當(dāng)horizontal={true}時(shí)(默認(rèn)值為false)复濒,否則為true
<ScrollView style={styles.scrollViewStyle} horizontal={true} alwaysBounceVertical={true} > {this.renderItem()} </ScrollView>
效果:
automaticallyAdjustContentInsets:如果滾動(dòng)視圖放在一個(gè)導(dǎo)航條或者工具條后面的時(shí)候畦木,iOS系統(tǒng)是否要自動(dòng)調(diào)整內(nèi)容的范圍十籍。默認(rèn)值為true。(譯注:如果你的ScrollView或ListView的頭部出現(xiàn)莫名其妙的空白围俘,嘗試將此屬性置為false)
-
bounces:當(dāng)值為true時(shí)楷拳,如果內(nèi)容范圍比滾動(dòng)視圖本身大,在到達(dá)內(nèi)容末尾的時(shí)候她混,可以彈性地拉動(dòng)一截坤按。如果為false臭脓,尾部的所有彈性都會(huì)被禁用,即使alwaysBounce*屬性為true嘹锁。默認(rèn)值為true
<ScrollView style={styles.scrollViewStyle} bounces={false} > {this.renderItem()} </ScrollView>
效果:
bouncesZoom:當(dāng)值為true時(shí),使用手勢縮放內(nèi)容可以超過min/max的限制摔竿,然后在手指抬起之后彈回min/max的縮放比例但金。否則的話冷溃,縮放不能超過限制
canCancelContentTouches:當(dāng)值為false時(shí),一旦有子節(jié)點(diǎn)響應(yīng)觸摸操作凿歼,即使手指開始移動(dòng)也不會(huì)拖動(dòng)滾動(dòng)視圖答憔。默認(rèn)值為true(在以上情況下可以拖動(dòng)滾動(dòng)視圖)
centerContent:當(dāng)值為true時(shí)虐拓,如果滾動(dòng)視圖的內(nèi)容比視圖本身小蓉驹,則會(huì)自動(dòng)把內(nèi)容居中放置。當(dāng)內(nèi)容比滾動(dòng)視圖大的時(shí)候瞻润,此屬性沒有作用绍撞。默認(rèn)值為false
contentInset:{top: number, left: number, bottom: number, right: number}內(nèi)容范圍相對(duì)滾動(dòng)視圖邊緣的坐標(biāo)。默認(rèn)為{0, 0, 0, 0}
contentOffset:用來手動(dòng)設(shè)置初始的滾動(dòng)坐標(biāo)。默認(rèn)值為{x: 0, y: 0}
-
decelerationRate:一個(gè)浮點(diǎn)數(shù),用于決定當(dāng)用戶抬起手指之后怪蔑,滾動(dòng)視圖減速停下的速度。常見的選項(xiàng)有:
- Normal: 0.998 (默認(rèn)值)
- Fast: 0.9
directionalLockEnabled:當(dāng)值為真時(shí)弓坞,滾動(dòng)視圖在拖拽的時(shí)候會(huì)鎖定只有垂直或水平方向可以滾動(dòng)渡冻。默認(rèn)值為false
maximumZoomScale:允許的最大縮放比例族吻。默認(rèn)值為1.0
minimumZoomScale:允許的最小縮放比例超歌。默認(rèn)值為1.0
-
pagingEnabled:當(dāng)值為true時(shí),滾動(dòng)條會(huì)停在滾動(dòng)視圖的尺寸的整數(shù)倍位置禀综。這個(gè)可以用在水平分頁上定枷。默認(rèn)值為false
<ScrollView style={styles.scrollViewStyle} horizontal={true} pagingEnabled={true} > {this.renderItem()} </ScrollView>
效果:
-
scrollEnabled:當(dāng)值為false的時(shí)候退子,內(nèi)容不能滾動(dòng)寂祥,默認(rèn)值為true
<ScrollView style={styles.scrollViewStyle} scrollEnabled={false} > {this.renderItem()} </ScrollView>
效果:
scrollEventThrottle:這個(gè)屬性控制在滾動(dòng)過程中福扬,scroll事件被調(diào)用的頻率(單位是每秒事件數(shù)量)铛碑。更大的數(shù)值能夠更及時(shí)的跟蹤滾動(dòng)位置涛菠,不過可能會(huì)帶來性能問題俗冻,因?yàn)楦嗟男畔?huì)通過bridge傳遞言疗。默認(rèn)值為0噪奄,意味著每次視圖被滾動(dòng),scroll事件只會(huì)被調(diào)用一次
scrollIndicatorInsets:{top: number, left: number, bottom: number, right: number}決定滾動(dòng)條距離視圖邊緣的坐標(biāo)碰缔。這個(gè)值應(yīng)該和contentInset一樣。默認(rèn)值為{0, 0, 0, 0}
-
scrollsToTop:當(dāng)此值為true時(shí)梗肝,點(diǎn)擊狀態(tài)欄的時(shí)候視圖會(huì)滾動(dòng)到頂部巫击。默認(rèn)值為true
<ScrollView style={styles.scrollViewStyle} scrollsToTop={true} > {this.renderItem()} </ScrollView>
效果:
-
snapToAlignment:enum('start', "center", 'end')當(dāng)設(shè)置了snapToInterval重付,snapToAlignment會(huì)定義停駐點(diǎn)與滾動(dòng)視圖之間的關(guān)系弓颈。
- start (默認(rèn)) 會(huì)將停駐點(diǎn)對(duì)齊在左側(cè)(水平)或頂部(垂直)
- center 會(huì)將停駐點(diǎn)對(duì)齊到中間
- end 會(huì)將停駐點(diǎn)對(duì)齊到右側(cè)(水平)或底部(垂直)
snapToInterval:當(dāng)設(shè)置了此屬性時(shí),會(huì)讓滾動(dòng)視圖滾動(dòng)停止后,停止在
snapToInterval
的倍數(shù)的位置橘蜜。這可以在一些子視圖比滾動(dòng)視圖本身小的時(shí)候用于實(shí)現(xiàn)分頁顯示snapToAlignment
組合使用-
stickyHeaderIndices:一個(gè)子視圖下標(biāo)的數(shù)組,用于決定哪些成員會(huì)在滾動(dòng)之后固定在屏幕頂端徽职。舉個(gè)例子说订,傳遞
stickyHeaderIndices={[0]}
會(huì)讓第一個(gè)成員固定在滾動(dòng)視圖頂端潮瓶。這個(gè)屬性不能和horizontal={true}
一起使用<ScrollView style={styles.scrollViewStyle} stickyHeaderIndices={[0]} > {this.renderItem()} </ScrollView>
效果:
zoomScale:滾動(dòng)視圖內(nèi)容初始的縮放比例陶冷。默認(rèn)值為1.0
onMomentumScrollEnd:當(dāng)一幀滾動(dòng)完畢的時(shí)候調(diào)用,通過
e.nativeEvent.contentOffset
獲取偏移量onScrollBeginDrag:當(dāng)開始手動(dòng)拖拽的時(shí)候調(diào)用
onScrollEndDrag:當(dāng)結(jié)束手動(dòng)拖拽的時(shí)候調(diào)用
onScrollAnimationEnd:當(dāng)滾動(dòng)動(dòng)畫結(jié)束之后調(diào)用此回調(diào)
-
onContentSizeChange:此函數(shù)會(huì)在ScrollView內(nèi)部可滾動(dòng)內(nèi)容的視圖發(fā)生變化時(shí)調(diào)用
- 調(diào)用參數(shù)為內(nèi)容視圖的寬和高: (contentWidth, contentHeight)
- 此方法是通過綁定在內(nèi)容容器上的onLayout來實(shí)現(xiàn)的
onScroll:在滾動(dòng)的過程中毯辅,每幀最多調(diào)用一次此回調(diào)函數(shù)埂伦。調(diào)用的頻率可以用scrollEventThrottle屬性來控制(在Android不好使,而且影響性能
)
方法
- scrollTo:(y: number | { x?: number, y?: number, animated?: boolean }, x: number, animated: boolean)滾動(dòng)到指定的x, y偏移處思恐。第三個(gè)參數(shù)為是否啟用平滑滾動(dòng)動(dòng)畫
ScrollView綜合使用實(shí)例
這邊通過所有
ScrollView
入門編程的經(jīng)典案例 —— 圖片輪播器更全面地理解ScrollView
的使用-
為了更貼切實(shí)際開發(fā)沾谜,這邊使用JSON來包裝圖片數(shù)據(jù)胀莹,內(nèi)容如下圖
-
先來實(shí)例化一個(gè)ScrollView與其內(nèi)部的子視圖,并進(jìn)行一些測試必要的設(shè)置
- 先獲取json中的數(shù)據(jù)
// 獲取json中的數(shù)據(jù) var imageData = require('./Data/ImageData.json');
- 接著我們來完成視圖部分
// 視圖 var CustomScrollView = React.createClass({ render(){ return( <View style={styles.container}> {/* 實(shí)例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開啟分頁功能 > {/* 實(shí)例化內(nèi)部子視圖 */} {this.renderItem()} </ScrollView> </View> ); }, // scrollView子視圖 renderItem() { var itemAry = []; // 獲取json中圖片 var imgAry = imageData.data; // 根據(jù)json數(shù)據(jù)實(shí)例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個(gè)對(duì)象 var item = imgAry[i]; // 將子視圖放進(jìn) itemAry itemAry.push( // 實(shí)例化子視圖 <Image key={i} style={styles.itemStyle} source={{uri:item.img}} /> ) } // 返回?cái)?shù)組 return itemAry; }, });
- 最后是樣式部分
// 樣式 var styles = StyleSheet.create({ container: { backgroundColor:'white' }, scrollViewStyle: { // 背景色 backgroundColor:'yellow', // 上邊距 marginTop:20 }, itemStyle: { // 尺寸 width:width, height:200, // 圖片等比例拉伸 resizeMode:'contain' }, });
效果:
- 先獲取json中的數(shù)據(jù)
-
圖片輪播器肯定要有分頁指示器漓概,接下來我們就來制作
- 視圖部分
// 先初始化頁碼,確定初始化后顯示哪個(gè)頁面 getInitialState(){ return{ // 初始化當(dāng)前頁碼 currentPage:0 } },
- 實(shí)例化一個(gè)分頁指示器
{/* 實(shí)例化分頁指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> // 分頁指示器 renderPagingIndicator() { var itemAry = [], autoColor; // 獲取json中圖片 var imgAry = imageData.data; // 根據(jù)json數(shù)據(jù)實(shí)例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個(gè)對(duì)象 var item = imgAry[i]; // 跟隨當(dāng)前頁改變對(duì)應(yīng) 點(diǎn) 的顏色 autoColor = (this.state.currentPage === i) ? {color:'orange'} : {color:'white'} // 將子視圖放進(jìn) itemAry itemAry.push( // 實(shí)例化視圖 <Text key={i} style={[{fontSize:30}, autoColor]}>?</Text> ) } // 返回?cái)?shù)組 return itemAry; },
- 樣式部分
pagingIndicatorStyle: { // 背景色(使背景色為全透明) backgroundColor:'rgba(255,255,255,0.0)', // 尺寸 width:width, // 主軸方向與對(duì)齊方式 flexDirection:'row', justifyContent:'center', // 絕對(duì)定位,使頁碼指示器蓋在scrollView上面 position:'absolute', bottom:0 }
效果:
- 視圖部分
-
最后將完整代碼放出隧期,供參考
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, ScrollView, Image } from 'react-native'; // 引入Dimensions庫 var Dimensions = require('Dimensions'); var {width, height} = Dimensions.get('window'); // 獲取json中的數(shù)據(jù) var imageData = require('./Data/ImageData.json'); // 視圖 var CustomScrollView = React.createClass({ // 先初始化頁碼,確定初始化后顯示哪個(gè)頁面 getInitialState(){ return{ // 初始化當(dāng)前頁碼 currentPage:0 } }, render(){ return( <View style={styles.container}> {/* 實(shí)例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開啟分頁功能 onMomentumScrollEnd={this.onAnimationEnd} // 當(dāng)一幀滾動(dòng)完畢的時(shí)候調(diào)用 > {/* 實(shí)例化內(nèi)部子視圖 */} {this.renderItem()} </ScrollView> {/* 實(shí)例化分頁指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> </View> ); }, // 監(jiān)聽滾動(dòng) onAnimationEnd(e){ // 求出水平方向上的偏移量 var offSetX = e.nativeEvent.contentOffset.x; // 計(jì)算當(dāng)前頁碼 var currentPage = offSetX / width; // 重新繪制UI this.setState({ currentPage:currentPage }); }, // 分頁指示器 renderPagingIndicator() { var itemAry = [], autoColor; // 獲取json中圖片 var imgAry = imageData.data; // 根據(jù)json數(shù)據(jù)實(shí)例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個(gè)對(duì)象 var item = imgAry[i]; // 跟隨當(dāng)前頁改變對(duì)應(yīng) 點(diǎn) 的顏色 autoColor = (this.state.currentPage === i) ? {color:'orange'} : {color:'white'} // 將子視圖放進(jìn) itemAry itemAry.push( // 實(shí)例化視圖 <Text key={i} style={[{fontSize:30}, autoColor]}>?</Text> ) } // 返回?cái)?shù)組 return itemAry; }, // scrollView子視圖 renderItem() { var itemAry = []; // 獲取json中圖片 var imgAry = imageData.data; // 根據(jù)json數(shù)據(jù)實(shí)例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個(gè)對(duì)象 var item = imgAry[i]; // 將子視圖放進(jìn) itemAry itemAry.push( // 實(shí)例化子視圖 <Image key={i} style={styles.itemStyle} source={{uri:item.img}} /> ) } // 返回?cái)?shù)組 return itemAry; }, }); // 樣式 var styles = StyleSheet.create({ container: { backgroundColor:'white' }, scrollViewStyle: { // 背景色 backgroundColor:'yellow', // 上邊距 marginTop:20 }, itemStyle: { // 尺寸 width:width, height:200, // 圖片等比例拉伸 resizeMode:'contain' }, pagingIndicatorStyle: { // 背景色(使背景色為全透明) backgroundColor:'rgba(255,255,255,0.0)', // 尺寸 width:width, // 主軸方向與對(duì)齊方式 flexDirection:'row', justifyContent:'center', // 絕對(duì)定位,使頁碼指示器蓋在scrollView上面 position:'absolute', bottom:0 } }); module.exports = CustomScrollView;
就先寫到這邊,如果有什么錯(cuò)誤還請(qǐng)朋友們指出,有什么不清楚的也歡迎留言,喜歡的話記得點(diǎn)贊哦派诬,謝謝!