前言
學(xué)習(xí)本系列內(nèi)容需要具備一定 HTML 開(kāi)發(fā)基礎(chǔ),沒(méi)有基礎(chǔ)的朋友可以先轉(zhuǎn)至 HTML快速入門(mén)(一) 學(xué)習(xí)
本人接觸 React Native 時(shí)間并不是特別長(zhǎng),所以對(duì)其中的內(nèi)容和性質(zhì)了解可能會(huì)有所偏差,在學(xué)習(xí)中如果有錯(cuò)會(huì)及時(shí)修改內(nèi)容,也歡迎萬(wàn)能的朋友們批評(píng)指出,謝謝
文章第一版出自簡(jiǎn)書(shū),如果出現(xiàn)圖片或頁(yè)面顯示問(wèn)題,煩請(qǐng)轉(zhuǎn)至 簡(jiǎn)書(shū) 查看 也希望喜歡的朋友可以點(diǎn)贊,謝謝
ScrollView組件介紹與簡(jiǎn)單使用
-
React Native中的
ScrollView的組件除了包裝滾動(dòng)平臺(tái),還集成了觸摸鎖定的響應(yīng)者系統(tǒng),使用的時(shí)候有幾點(diǎn)需要注意- ScrollView 必須有一個(gè)確定的高度才能正常工作,對(duì)于
ScrollView來(lái)說(shuō),它就是將一些不確定高度的子組件裝進(jìn)確定高度的容器 - 初始化的2中方式
- 不要給
ScrollView中不要加 [flex:1] - 直接給該
ScrollView設(shè)置高度(不建議),因?yàn)樗鼤?huì)根據(jù)內(nèi)部組件自動(dòng)延伸自己的尺寸到合適的大小
- 不要給
- ScrollView 內(nèi)部的其它響應(yīng)者沒(méi)辦法阻止 ScrollView 本身成為響應(yīng)者(也就是說(shuō),ScrollView 響應(yīng)的優(yōu)先級(jí)比內(nèi)部組件高,且內(nèi)部組件沒(méi)辦法改變優(yōu)先級(jí))
- ScrollView 必須有一個(gè)確定的高度才能正常工作,對(duì)于
-
那么就先來(lái)看看怎么創(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基本使用.gif - 視圖部分
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>效果:
horizontal屬性.gif -
keyboardDismissMode:用戶拖拽滾動(dòng)視圖的時(shí)候,是否要隱藏軟鍵盤(pán)。
- none(默認(rèn)值),拖拽時(shí)不隱藏軟鍵盤(pán)
- on-drag 當(dāng)拖拽開(kāi)始的時(shí)候隱藏軟鍵盤(pán)
- interactive 軟鍵盤(pán)伴隨拖拽操作同步地消失,并且如果往上滑動(dòng)會(huì)恢復(fù)鍵盤(pán)。安卓設(shè)備上不支持這個(gè)選項(xiàng),會(huì)表現(xiàn)的和none一樣。
keyboardShouldPersistTaps:當(dāng)此屬性為false的時(shí)候,在軟鍵盤(pán)激活之后,點(diǎn)擊焦點(diǎn)文本輸入框以外的地方,鍵盤(pán)就會(huì)隱藏。如果為true,滾動(dòng)視圖不會(huì)響應(yīng)點(diǎn)擊操作,并且鍵盤(pá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>效果:
顯示水平滾動(dòng)條.png -
showsVerticalScrollIndicator:當(dāng)此屬性為true的時(shí)候,顯示一個(gè)垂直方向的滾動(dòng)條
<ScrollView style={styles.scrollViewStyle} showsVerticalScrollIndicator={true} > {this.renderItem()} </ScrollView>效果:
顯示垂直滾動(dòng)條.png endFillColor:有時(shí)候滾動(dòng)視圖會(huì)占據(jù)比實(shí)際內(nèi)容更多的空間。這種情況下可以使用此屬性,指定以某種顏色來(lái)填充多余的空間,以避免設(shè)置背景和創(chuàng)建不必要的繪制開(kāi)銷(xiāo)。一般情況下并不需要這種高級(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>效果:
alwaysBounceHorizontal屬性.gif -
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>效果:
alwaysBounceVertical屬性.gif 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>效果:
bounces屬性為false時(shí).gif bouncesZoom:當(dāng)值為true時(shí),使用手勢(shì)縮放內(nèi)容可以超過(guò)min/max的限制,然后在手指抬起之后彈回min/max的縮放比例。否則的話,縮放不能超過(guò)限制
canCancelContentTouches:當(dāng)值為false時(shí),一旦有子節(jié)點(diǎn)響應(yīng)觸摸操作,即使手指開(kāi)始移動(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í)候,此屬性沒(méi)有作用。默認(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:用來(lái)手動(dòng)設(shè)置初始的滾動(dòng)坐標(biāo)。默認(rèn)值為{x: 0, y: 0}
-
decelerationRate:一個(gè)浮點(diǎn)數(shù),用于決定當(dāng)用戶抬起手指之后,滾動(dòng)視圖減速停下的速度。常見(jiàn)的選項(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è)可以用在水平分頁(yè)上。默認(rèn)值為false
<ScrollView style={styles.scrollViewStyle} horizontal={true} pagingEnabled={true} > {this.renderItem()} </ScrollView>效果:
pagingEnabled分頁(yè)屬性.gif -
scrollEnabled:當(dāng)值為false的時(shí)候,內(nèi)容不能滾動(dòng),默認(rèn)值為true
<ScrollView style={styles.scrollViewStyle} scrollEnabled={false} > {this.renderItem()} </ScrollView>效果:
scrollEnabled屬性為false時(shí)不能滾動(dòng).gif scrollEventThrottle:這個(gè)屬性控制在滾動(dòng)過(guò)程中,scroll事件被調(diào)用的頻率(單位是每秒事件數(shù)量)。更大的數(shù)值能夠更及時(shí)的跟蹤滾動(dòng)位置,不過(guò)可能會(huì)帶來(lái)性能問(wèn)題,因?yàn)楦嗟男畔?huì)通過(guò)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>效果:
scrollsToTop為true時(shí)點(diǎn)擊狀態(tài)欄可快速回到頂部.gif -
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)分頁(yè)顯示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>效果:
stickyHeaderIndices屬性.gif zoomScale:滾動(dòng)視圖內(nèi)容初始的縮放比例。默認(rèn)值為1.0
onMomentumScrollEnd:當(dāng)一幀滾動(dòng)完畢的時(shí)候調(diào)用,通過(guò)
e.nativeEvent.contentOffset獲取偏移量onScrollBeginDrag:當(dāng)開(kāi)始手動(dòng)拖拽的時(shí)候調(diào)用
onScrollEndDrag:當(dāng)結(jié)束手動(dòng)拖拽的時(shí)候調(diào)用
onScrollAnimationEnd:當(dāng)滾動(dòng)動(dòng)畫(huà)結(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)
- 此方法是通過(guò)綁定在內(nèi)容容器上的onLayout來(lái)實(shí)現(xiàn)的
onScroll:在滾動(dòng)的過(guò)程中,每幀最多調(diào)用一次此回調(diào)函數(shù)。調(diào)用的頻率可以用scrollEventThrottle屬性來(lái)控制(在Android不好使,而且影響性能
)
方法
- scrollTo:(y: number | { x?: number, y?: number, animated?: boolean }, x: number, animated: boolean)滾動(dòng)到指定的x, y偏移處。第三個(gè)參數(shù)為是否啟用平滑滾動(dòng)動(dòng)畫(huà)
ScrollView綜合使用實(shí)例
這邊通過(guò)所有
ScrollView入門(mén)編程的經(jīng)典案例 —— 圖片輪播器更全面地理解ScrollView的使用-
為了更貼切實(shí)際開(kāi)發(fā),這邊使用JSON來(lái)包裝圖片數(shù)據(jù),內(nèi)容如下圖
JSON數(shù)據(jù)詳情.png -
先來(lái)實(shí)例化一個(gè)ScrollView與其內(nèi)部的子視圖,并進(jìn)行一些測(cè)試必要的設(shè)置
- 先獲取json中的數(shù)據(jù)
// 獲取json中的數(shù)據(jù) var imageData = require('./Data/ImageData.json');- 接著我們來(lái)完成視圖部分
// 視圖 var CustomScrollView = React.createClass({ render(){ return( <View style={styles.container}> {/* 實(shí)例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開(kāi)啟分頁(yè)功能 > {/* 實(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ù)

-
圖片輪播器肯定要有分頁(yè)指示器,接下來(lái)我們就來(lái)制作
- 視圖部分
// 先初始化頁(yè)碼,確定初始化后顯示哪個(gè)頁(yè)面 getInitialState(){ return{ // 初始化當(dāng)前頁(yè)碼 currentPage:0 } },- 實(shí)例化一個(gè)分頁(yè)指示器
{/* 實(shí)例化分頁(yè)指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> // 分頁(yè)指示器 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)前頁(yè)改變對(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ì)定位,使頁(yè)碼指示器蓋在scrollView上面 position:'absolute', bottom:0 }效果:
- 視圖部分

-
最后將完整代碼放出,供參考
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, ScrollView, Image } from 'react-native'; // 引入Dimensions庫(kù) var Dimensions = require('Dimensions'); var {width, height} = Dimensions.get('window'); // 獲取json中的數(shù)據(jù) var imageData = require('./Data/ImageData.json'); // 視圖 var CustomScrollView = React.createClass({ // 先初始化頁(yè)碼,確定初始化后顯示哪個(gè)頁(yè)面 getInitialState(){ return{ // 初始化當(dāng)前頁(yè)碼 currentPage:0 } }, render(){ return( <View style={styles.container}> {/* 實(shí)例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開(kāi)啟分頁(yè)功能 onMomentumScrollEnd={this.onAnimationEnd} // 當(dāng)一幀滾動(dòng)完畢的時(shí)候調(diào)用 > {/* 實(shí)例化內(nèi)部子視圖 */} {this.renderItem()} </ScrollView> {/* 實(shí)例化分頁(yè)指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> </View> ); }, // 監(jiān)聽(tīng)滾動(dòng) onAnimationEnd(e){ // 求出水平方向上的偏移量 var offSetX = e.nativeEvent.contentOffset.x; // 計(jì)算當(dāng)前頁(yè)碼 var currentPage = offSetX / width; // 重新繪制UI this.setState({ currentPage:currentPage }); }, // 分頁(yè)指示器 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)前頁(yè)改變對(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ì)定位,使頁(yè)碼指示器蓋在scrollView上面 position:'absolute', bottom:0 } }); module.exports = CustomScrollView; 就先寫(xiě)到這邊,如果有什么錯(cuò)誤還請(qǐng)朋友們指出,有什么不清楚的也歡迎留言,喜歡的話記得點(diǎn)贊哦,謝謝!











