前言
學習本系列內容需要具備一定 HTML 開發基礎,沒有基礎的朋友可以先轉至 HTML快速入門(一) 學習
本人接觸 React Native 時間並不是特別長,所以對其中的內容和性質瞭解可能會有所偏差,在學習中如果有錯會及時修改內容,也歡迎萬能的朋友們批評指出,謝謝
文章第一版出自簡書,如果出現圖片或頁面顯示問題,煩請轉至 簡書 查看 也希望喜歡的朋友可以點贊,謝謝
ScrollView組件介紹與簡單使用
- React Native中的
ScrollView
的組件除了包裝滾動平臺,還集成了觸摸鎖定的響應者
系統,使用的時候有幾點需要注意
- ScrollView 必須有一個確定的高度才能正常工作,對於
ScrollView
來說,它就是將一些不確定高度的子組件裝進確定高度的容器 - 初始化的2中方式
- 不要給
ScrollView
中不要加 [flex:1] - 直接給該
ScrollView
設置高度(不建議),因爲它會根據內部組件自動延伸自己的尺寸到合適的大小
- 不要給
- ScrollView 內部的其它響應者沒辦法阻止 ScrollView 本身成爲響應者(也就是說,ScrollView 響應的優先級比內部組件高,且內部組件沒辦法改變優先級)
- ScrollView 必須有一個確定的高度才能正常工作,對於
那麼就先來看看怎麼創建基本的
ScrollView
- 視圖部分
// 視圖 var CustomScrollView = React.createClass({ render(){ return( <ScrollView style={styles.mainStyle}> {this.renderItem()} </ScrollView> ); }, renderItem() { // 數組 var itemAry = []; // 顏色數組 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 中常用的屬性
下面經常使用和比較難理解的屬性會有示例代碼或效果圖
contentContainerStyle:這些樣式會引用到一個內層的內容容器上,所有的子視圖都會包裹在內容容器內
horizontal:當此屬性爲true的時候,所有的的子視圖會在水平方向上排成一行,而不是默認的在垂直方向上排成一列。默認值爲false
<ScrollView style={styles.scrollViewStyle} horizontal={true} > {this.renderItem()} </ScrollView>
效果:
keyboardDismissMode:用戶拖拽滾動視圖的時候,是否要隱藏軟鍵盤。
- none(默認值),拖拽時不隱藏軟鍵盤
- on-drag 當拖拽開始的時候隱藏軟鍵盤
- interactive 軟鍵盤伴隨拖拽操作同步地消失,並且如果往上滑動會恢復鍵盤。安卓設備上不支持這個選項,會表現的和none一樣。
keyboardShouldPersistTaps:當此屬性爲false的時候,在軟鍵盤激活之後,點擊焦點文本輸入框以外的地方,鍵盤就會隱藏。如果爲true,滾動視圖不會響應點擊操作,並且鍵盤不會自動消失。默認值爲false
refreshControl:指定RefreshControl組件,用於爲ScrollView提供下拉刷新功能
removeClippedSubviews:(實驗特性)當此屬性爲true時,屏幕之外的子視圖(子視圖的overflow樣式需要設爲hidden)會被移除。這個可以提升大列表的滾動性能。默認值爲true
var styles = StyleSheet.create({ child: { ... // 因爲默認爲true,所以我們只需要在子視圖將下面樣式設爲hidden就可以了 overflow: 'hidden' }, });
showsHorizontalScrollIndicator:當此屬性爲true的時候,顯示一個水平方向的滾動條
<ScrollView style={styles.scrollViewStyle} horizontal={true} showsHorizontalScrollIndicator={true} > {this.renderItem()} </ScrollView>
效果:
showsVerticalScrollIndicator:當此屬性爲true的時候,顯示一個垂直方向的滾動條
<ScrollView style={styles.scrollViewStyle} showsVerticalScrollIndicator={true} > {this.renderItem()} </ScrollView>
效果:
endFillColor:有時候滾動視圖會佔據比實際內容更多的空間。這種情況下可以使用此屬性,指定以某種顏色來填充多餘的空間,以避免設置背景和創建不必要的繪製開銷。一般情況下並不需要這種高級優化技巧
alwaysBounceHorizontal:當此屬性爲true時,水平方向即使內容比滾動視圖本身還要小,也可以彈性地拉動一截。當horizontal={true}時(默認值爲true)否則爲false
<ScrollView style={styles.scrollViewStyle} horizontal={true} alwaysBounceHorizontal={true} > {this.renderItem()} </ScrollView>
效果:
alwaysBounceVertical:當此屬性爲true時,垂直方向即使內容比滾動視圖本身還要小,也可以彈性地拉動一截。當horizontal={true}時(默認值爲false),否則爲true
<ScrollView style={styles.scrollViewStyle} horizontal={true} alwaysBounceVertical={true} > {this.renderItem()} </ScrollView>
效果:
automaticallyAdjustContentInsets:如果滾動視圖放在一個導航條或者工具條後面的時候,iOS系統是否要自動調整內容的範圍。默認值爲true。(譯註:如果你的ScrollView或ListView的頭部出現莫名其妙的空白,嘗試將此屬性置爲false)
bounces:當值爲true時,如果內容範圍比滾動視圖本身大,在到達內容末尾的時候,可以彈性地拉動一截。如果爲false,尾部的所有彈性都會被禁用,即使alwaysBounce*屬性爲true。默認值爲true
<ScrollView style={styles.scrollViewStyle} bounces={false} > {this.renderItem()} </ScrollView>
效果:
bouncesZoom:當值爲true時,使用手勢縮放內容可以超過min/max的限制,然後在手指擡起之後彈回min/max的縮放比例。否則的話,縮放不能超過限制
canCancelContentTouches:當值爲false時,一旦有子節點響應觸摸操作,即使手指開始移動也不會拖動滾動視圖。默認值爲true(在以上情況下可以拖動滾動視圖)
centerContent:當值爲true時,如果滾動視圖的內容比視圖本身小,則會自動把內容居中放置。當內容比滾動視圖大的時候,此屬性沒有作用。默認值爲false
contentInset:{top: number, left: number, bottom: number, right: number}內容範圍相對滾動視圖邊緣的座標。默認爲{0, 0, 0, 0}
contentOffset:用來手動設置初始的滾動座標。默認值爲{x: 0, y: 0}
decelerationRate:一個浮點數,用於決定當用戶擡起手指之後,滾動視圖減速停下的速度。常見的選項有:
- Normal: 0.998 (默認值)
- Fast: 0.9
directionalLockEnabled:當值爲真時,滾動視圖在拖拽的時候會鎖定只有垂直或水平方向可以滾動。默認值爲false
maximumZoomScale:允許的最大縮放比例。默認值爲1.0
minimumZoomScale:允許的最小縮放比例。默認值爲1.0
pagingEnabled:當值爲true時,滾動條會停在滾動視圖的尺寸的整數倍位置。這個可以用在水平分頁上。默認值爲false
<ScrollView style={styles.scrollViewStyle} horizontal={true} pagingEnabled={true} > {this.renderItem()} </ScrollView>
效果:
scrollEnabled:當值爲false的時候,內容不能滾動,默認值爲true
<ScrollView style={styles.scrollViewStyle} scrollEnabled={false} > {this.renderItem()} </ScrollView>
效果:
scrollEventThrottle:這個屬性控制在滾動過程中,scroll事件被調用的頻率(單位是每秒事件數量)。更大的數值能夠更及時的跟蹤滾動位置,不過可能會帶來性能問題,因爲更多的信息會通過bridge傳遞。默認值爲0,意味着每次視圖被滾動,scroll事件只會被調用一次
scrollIndicatorInsets:{top: number, left: number, bottom: number, right: number}決定滾動條距離視圖邊緣的座標。這個值應該和contentInset一樣。默認值爲{0, 0, 0, 0}
scrollsToTop:當此值爲true時,點擊狀態欄的時候視圖會滾動到頂部。默認值爲true
<ScrollView style={styles.scrollViewStyle} scrollsToTop={true} > {this.renderItem()} </ScrollView>
效果:
snapToAlignment:enum(‘start’, “center”, ‘end’)當設置了snapToInterval,snapToAlignment會定義停駐點與滾動視圖之間的關係。
- start (默認) 會將停駐點對齊在左側(水平)或頂部(垂直)
- center 會將停駐點對齊到中間
- end 會將停駐點對齊到右側(水平)或底部(垂直)
snapToInterval:當設置了此屬性時,會讓滾動視圖滾動停止後,停止在
snapToInterval
的倍數的位置。這可以在一些子視圖比滾動視圖本身小的時候用於實現分頁顯示snapToAlignment
組合使用stickyHeaderIndices:一個子視圖下標的數組,用於決定哪些成員會在滾動之後固定在屏幕頂端。舉個例子,傳遞
stickyHeaderIndices={[0]}
會讓第一個成員固定在滾動視圖頂端。這個屬性不能和horizontal={true}
一起使用<ScrollView style={styles.scrollViewStyle} stickyHeaderIndices={[0]} > {this.renderItem()} </ScrollView>
效果:
zoomScale:滾動視圖內容初始的縮放比例。默認值爲1.0
onMomentumScrollEnd:當一幀滾動完畢的時候調用,通過
e.nativeEvent.contentOffset
獲取偏移量onScrollBeginDrag:當開始手動拖拽的時候調用
onScrollEndDrag:當結束手動拖拽的時候調用
onScrollAnimationEnd:當滾動動畫結束之後調用此回調
onContentSizeChange:此函數會在ScrollView內部可滾動內容的視圖發生變化時調用
- 調用參數爲內容視圖的寬和高: (contentWidth, contentHeight)
- 此方法是通過綁定在內容容器上的onLayout來實現的
onScroll:在滾動的過程中,每幀最多調用一次此回調函數。調用的頻率可以用scrollEventThrottle屬性來控制(在Android不好使,而且影響性能
- )
方法
- scrollTo:(y: number | { x?: number, y?: number, animated?: boolean }, x: number, animated: boolean)滾動到指定的x, y偏移處。第三個參數爲是否啓用平滑滾動動畫
ScrollView綜合使用實例
- 這邊通過所有
ScrollView
入門編程的經典案例 —— 圖片輪播器更全面地理解ScrollView
的使用 爲了更貼切實際開發,這邊使用JSON來包裝圖片數據,內容如下圖
先來實例化一個ScrollView與其內部的子視圖,並進行一些測試必要的設置
- 先獲取json中的數據
// 獲取json中的數據 var imageData = require('./Data/ImageData.json');
- 接着我們來完成視圖部分
// 視圖 var CustomScrollView = React.createClass({ render(){ return( <View style={styles.container}> {/* 實例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開啓分頁功能 > {/* 實例化內部子視圖 */} {this.renderItem()} </ScrollView> </View> ); }, // scrollView子視圖 renderItem() { var itemAry = []; // 獲取json中圖片 var imgAry = imageData.data; // 根據json數據實例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個對象 var item = imgAry[i]; // 將子視圖放進 itemAry itemAry.push( // 實例化子視圖 <Image key={i} style={styles.itemStyle} source={{uri:item.img}} /> ) } // 返回數組 return itemAry; }, });
- 最後是樣式部分
// 樣式 var styles = StyleSheet.create({ container: { backgroundColor:'white' }, scrollViewStyle: { // 背景色 backgroundColor:'yellow', // 上邊距 marginTop:20 }, itemStyle: { // 尺寸 width:width, height:200, // 圖片等比例拉伸 resizeMode:'contain' }, });
效果:
- 先獲取json中的數據
圖片輪播器肯定要有分頁指示器,接下來我們就來製作
- 視圖部分
// 先初始化頁碼,確定初始化後顯示哪個頁面 getInitialState(){ return{ // 初始化當前頁碼 currentPage:0 } },
- 實例化一個分頁指示器
{/* 實例化分頁指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> // 分頁指示器 renderPagingIndicator() { var itemAry = [], autoColor; // 獲取json中圖片 var imgAry = imageData.data; // 根據json數據實例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個對象 var item = imgAry[i]; // 跟隨當前頁改變對應 點 的顏色 autoColor = (this.state.currentPage === i) ? {color:'orange'} : {color:'white'} // 將子視圖放進 itemAry itemAry.push( // 實例化視圖 <Text key={i} style={[{fontSize:30}, autoColor]}>•</Text> ) } // 返回數組 return itemAry; },
- 樣式部分
pagingIndicatorStyle: { // 背景色(使背景色爲全透明) backgroundColor:'rgba(255,255,255,0.0)', // 尺寸 width:width, // 主軸方向與對齊方式 flexDirection:'row', justifyContent:'center', // 絕對定位,使頁碼指示器蓋在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中的數據 var imageData = require('./Data/ImageData.json'); // 視圖 var CustomScrollView = React.createClass({ // 先初始化頁碼,確定初始化後顯示哪個頁面 getInitialState(){ return{ // 初始化當前頁碼 currentPage:0 } }, render(){ return( <View style={styles.container}> {/* 實例化ScrollView */} <ScrollView style={styles.scrollViewStyle} horizontal={true} // 水平方向 showsHorizontalScrollIndicator={false} // 隱藏水平指示器 showsVerticalScrollIndicator={false} // 隱藏垂直指示器 pagingEnabled={true} // 開啓分頁功能 onMomentumScrollEnd={this.onAnimationEnd} // 當一幀滾動完畢的時候調用 > {/* 實例化內部子視圖 */} {this.renderItem()} </ScrollView> {/* 實例化分頁指示器 */} <View style={styles.pagingIndicatorStyle}> {this.renderPagingIndicator()} </View> </View> ); }, // 監聽滾動 onAnimationEnd(e){ // 求出水平方向上的偏移量 var offSetX = e.nativeEvent.contentOffset.x; // 計算當前頁碼 var currentPage = offSetX / width; // 重新繪製UI this.setState({ currentPage:currentPage }); }, // 分頁指示器 renderPagingIndicator() { var itemAry = [], autoColor; // 獲取json中圖片 var imgAry = imageData.data; // 根據json數據實例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個對象 var item = imgAry[i]; // 跟隨當前頁改變對應 點 的顏色 autoColor = (this.state.currentPage === i) ? {color:'orange'} : {color:'white'} // 將子視圖放進 itemAry itemAry.push( // 實例化視圖 <Text key={i} style={[{fontSize:30}, autoColor]}>•</Text> ) } // 返回數組 return itemAry; }, // scrollView子視圖 renderItem() { var itemAry = []; // 獲取json中圖片 var imgAry = imageData.data; // 根據json數據實例化視圖 for (var i = 0; i<imgAry.length; i++) { // 取出單個對象 var item = imgAry[i]; // 將子視圖放進 itemAry itemAry.push( // 實例化子視圖 <Image key={i} style={styles.itemStyle} source={{uri:item.img}} /> ) } // 返回數組 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, // 主軸方向與對齊方式 flexDirection:'row', justifyContent:'center', // 絕對定位,使頁碼指示器蓋在scrollView上面 position:'absolute', bottom:0 } }); module.exports = CustomScrollView;
- 就先寫到這邊,如果有什麼錯誤還請朋友們指出,有什麼不清楚的也歡迎留言,喜歡的話記得點贊哦,謝謝!