React Native之ScrollView控制元件詳解
概述
ScrollView在Android和ios原生開發中都比較常見,是一個 滾動檢視控制元件。在RN開發中,系統也給我們提供了這麼一個控制元件。不過在RN開發中 ,使用ScrollView必須有一個確定的高度才能正常工作,因為它實際上所做的就是將一系列不確定高度的子元件裝進一個確定高度的容器(通過滾動操作)。
所以,要給一個ScrollView確定一個高度的話,要麼直接給它設定高度(不建議),要麼確定所有的父容器都已經綁定了高度。在檢視棧的任意一個位置忘記使用{flex:1}都會導致錯誤。
ScrollView內部的其他響應者尚無法阻止ScrollView本身成為響應者。
屬性
1:contentContainerStyle StyleSheetPropType(ViewStylePropTypes)
這些樣式會應用到一個內層的內容容器上,所有的子檢視都會包裹在內容容器內。例子:
return (
<ScrollView contentContainerStyle={styles.contentContainer}>
</ScrollView>
);
...
var styles = StyleSheet.create({
contentContainer: {
paddingVertical: 20
}
});
2:horizontal bool
當此屬性為true的時候,所有的的子檢視會在水平方向上排成一行,而不是預設的在垂直方向上排成一列。預設值為false。
3:keyboardDismissMode enum(‘none’, “interactive”, ‘on-drag’)
使用者拖拽滾動檢視的時候,是否要隱藏軟鍵盤。
4:none(預設值),拖拽時不隱藏軟鍵盤。
5:on-drag 當拖拽開始的時候隱藏軟鍵盤。
6:interactive 軟鍵盤伴隨拖拽操作同步地消失,並且如果往上滑動會恢復鍵盤。安卓裝置上不支援這個選項,會表現的和none一樣。
7:keyboardShouldPersistTaps bool
當此屬性為false的時候,在軟鍵盤啟用之後,點選焦點文字輸入框以外的地方,鍵盤就會隱藏。如果為true,滾動檢視不會響應點選操作,並且鍵盤不會自動消失。預設值為false。
8:onContentSizeChange function
此函式會在ScrollView內部可滾動內容的檢視發生變化時呼叫。
呼叫引數為內容檢視的寬和高: (contentWidth, contentHeight)
此方法是通過繫結在內容容器上的onLayout來實現的。
9:onScroll function
在滾動的過程中,每幀最多呼叫一次此回撥函式。呼叫的頻率可以用scrollEventThrottle屬性來控制。
10:refreshControl element
指定RefreshControl元件,用於為ScrollView提供下拉重新整理功能。
11:removeClippedSubviews bool
(實驗特性):當此屬性為true時,螢幕之外的子檢視(子檢視的overflow樣式需要設為hidden)會被移除。這個可以提升大列表的滾動效能。預設值為true。
12:showsHorizontalScrollIndicator bool
當此屬性為true的時候,顯示一個水平方向的滾動條。
13:showsVerticalScrollIndicator bool
當此屬性為true的時候,顯示一個垂直方向的滾動條。
有時候滾動檢視會佔據比實際內容更多的空間。這種情況下可以使用此屬性,指定以某種顏色來填充多餘的空間,以避免設定背景和建立不必要的繪製開銷。一般情況下並不需要這種高階優化技巧。
14:(ios)alwaysBounceHorizontal bool
當此屬性為true時,水平方向即使內容比滾動檢視本身還要小,也可以彈性地拉動一截。當horizontal={true}時預設值為true,否則為false。
15:(ios)alwaysBounceVertical bool
當此屬性為true時,垂直方向即使內容比滾動檢視本身還要小,也可以彈性地拉動一截。當horizontal={true}時預設值為false,否則為true。
16:(ios)automaticallyAdjustContentInsets bool
如果滾動檢視放在一個導航條或者工具條後面的時候,iOS系統是否要自動調整內容的範圍。預設值為true。(譯註:如果你的ScrollView或ListView的頭部出現莫名其妙的空白,嘗試將此屬性置為false)
18:(ios)bounces bool
當值為true時,如果內容範圍比滾動檢視本身大,在到達內容末尾的時候,可以彈性地拉動一截。如果為false,尾部的所有彈性都會被禁用,即使alwaysBounce*屬性為true。預設值為true。
19:(ios)bouncesZoom bool
當值為true時,使用手勢縮放內容可以超過min/max的限制,然後在手指擡起之後彈回min/max的縮放比例。否則的話,縮放不能超過限制。
20:(ios)canCancelContentTouches bool
當值為false時,一旦有子節點響應觸控操作,即使手指開始移動也不會拖動滾動檢視。預設值為true(在以上情況下可以拖動滾動檢視。)
21:(ios)centerContent bool
當值為true時,如果滾動檢視的內容比檢視本身小,則會自動把內容居中放置。當內容比滾動檢視大的時候,此屬性沒有作用。預設值為false。
22:(ios)contentInset {top: number, left: number, bottom: number, right: number}
內容範圍相對滾動檢視邊緣的座標。預設為{0, 0, 0, 0}。
23:(ios)contentOffset PointPropType
用來手動設定初始的滾動座標。預設值為{x: 0, y: 0}。
24:(ios)decelerationRate number
一個浮點數,用於決定當使用者擡起手指之後,滾動檢視減速停下的速度。常見的選項有:
Normal: 0.998 (預設值)
Fast: 0.9
25:(ios)directionalLockEnabled bool
當值為真時,滾動檢視在拖拽的時候會鎖定只有垂直或水平方向可以滾動。預設值為false。
26:(ios)maximumZoomScale number
允許的最大縮放比例。預設值為1.0。
27:(ios)minimumZoomScale number
允許的最小縮放比例。預設值為1.0。
28:(ios)onRefreshStart function
已過期
請使用refreshControl 屬性代替。
29:(ios)onScrollAnimationEnd function
當滾動動畫結束之後呼叫此回撥。
30:pagingEnabled bool
當值為true時,滾動條會停在滾動檢視的尺寸的整數倍位置。這個可以用在水平分頁上。預設值為false。
31:(ios)scrollEnabled bool
當值為false的時候,內容不能滾動,預設值為true。
32:(ios)scrollEventThrottle number
這個屬性控制在滾動過程中,scroll事件被呼叫的頻率(單位是每秒事件數量)。更大的數值能夠更及時的跟蹤滾動位置,不過可能會帶來效能問題,因為更多的資訊會通過bridge傳遞。預設值為0,意味著每次檢視被滾動,scroll事件只會被呼叫一次。
33:(ios)scrollIndicatorInsets {top: number, left: number, bottom: number, right: number}
決定滾動條距離檢視邊緣的座標。這個值應該和contentInset一樣。預設值為{0, 0, 0, 0}。
34:(ios)scrollsToTop bool
當此值為true時,點選狀態列的時候檢視會滾動到頂部。預設值為true。
35:(ios)snapToAlignment enum(‘start’, “center”, ‘end’)
當設定了snapToInterval,snapToAlignment會定義停駐點與滾動檢視之間的關係。
36:start (預設) 會將停駐點對齊在左側(水平)或頂部(垂直)
37:center 會將停駐點對齊到中間
38:end 會將停駐點對齊到右側(水平)或底部(垂直)
39:(ios)snapToInterval number
當設定了此屬性時,會讓滾動檢視滾動停止後,停止在snapToInterval的倍數的位置。這可以在一些子檢視比滾動檢視本身小的時候用於實現分頁顯示。與snapToAlignment組合使用。
40:(ios)stickyHeaderIndices [number]
一個子檢視下標的陣列,用於決定哪些成員會在滾動之後固定在螢幕頂端。舉個例子,傳遞stickyHeaderIndices={[0]}會讓第一個成員固定在滾動檢視頂端。這個屬性不能和horizontal={true}一起使用。
41:(ios)zoomScale number
滾動檢視內容初始的縮放比例。預設值為1.0。
ScrollView程式碼
程式碼實現:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
ScrollView,
TouchableOpacity,
} from 'react-native';
class ScrollViewDemo extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.title_view}>
<Text style={styles.title_text}>
空間動態
</Text>
</View>
<ScrollView ref={(scrollView) => { _scrollView = scrollView; }}>
<View style={styles.three_image_view}>
<View style={styles.vertical_view}>
<Image source={require('./img/igs.png')} style={{alignSelf:'center',width:45,height:45}} />
<Text style={styles.top_text}>
好友動態
</Text>
</View>
<View style={styles.vertical_view}>
<Image source={require('./img/eqc.png')} style={{alignSelf:'center',width:45,height:45}}/>
<Text style={styles.top_text}>
附近
</Text>
</View>
<View style={styles.vertical_view}>
<Image source={require('./img/iei.png')} style={{alignSelf:'center',width:45,height:45}}/>
<Text style={styles.top_text} >
興趣部落
</Text>
</View>
</View>
<View style={{height:30,backgroundColor:'#f9f9fb'}}/>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsa.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
羽毛球
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nsb.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
火車票
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
<View style={styles.rectangle_view}>
<View style={{flexDirection:'row',alignItems: 'center'}}>
<Image source={require('./img/nrz.png')} style={{alignSelf:'center',width:30,height:30}}/>
<Text style={styles.rectangle_text} >
視訊
</Text>
</View>
<Image source={require('./img/ppe.png')} style={{alignSelf:'center',width:20,height:20}}/>
</View>
</ScrollView>
<TouchableOpacity
style={styles.button}
onPress={() => { _scrollView.scrollTo({y: 0}); }}>
<Text>讓我滾回去</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
title_view:{
flexDirection:'row',
height:50,
justifyContent: 'center',
alignItems: 'center',
backgroundColor:'#27b5ee',
},
title_text:{
color:'white',
fontSize:20,
textAlign:'center'
},
three_image_view:{
paddingTop: 15,
flexDirection:'row',
justifyContent: 'space-around',
alignItems: 'center',
backgroundColor:'white',
},
vertical_view:{
justifyContent: 'center',
alignItems: 'center',
backgroundColor:'white',
paddingBottom:15,
},
top_text:{
marginTop:5,
color:'black',
fontSize:16,
textAlign:'center'
},
rectangle_view:{
paddingTop:8,
paddingBottom:8,
paddingLeft:15,
paddingRight:15,
flexDirection:'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor:'white',
borderBottomColor:'#dedfe0',
borderBottomWidth:1,
},
rectangle_text:{
color:'black',
fontSize:16,
textAlign:'center',
paddingLeft:8,
},
button: {
margin: 7,
padding: 5,
alignItems: 'center',
backgroundColor: '#eaeaea',
borderRadius: 3,
},
});
AppRegistry.registerComponent('ScrollViewDemo', () => ScrollViewDemo);
其實我們單就這種效果來說,我們可以直接用ListView做,不過了為講解ScrollView這這麼實現吧。
又如使用ScrollView實現一個簡單的廣告欄(當然我們可以使用第三方元件react-native-swiper)。如圖:
完整程式碼:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow 廣告檢視封裝
*/
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
Image,
ScrollView,
View
} from 'react-native';
var Dimensions = require('Dimensions');
var screenWidth = Dimensions.get('window').width;
var imageData = [
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2263582212.jpg',
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2265761240.jpg',
'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2266110047.jpg'
];
class HorizontalScrollView extends Component {
constructor(props) {
super(props);
this.state = {currentPage: 0};
}
render() {
return (
<View style={styles.container}>
<ScrollView
ref='scrollView'
horizontal={true}
showsHorizontalScrollIndicator={false}
pagingEnabled={true}
onMomentumScrollEnd={(e) => {
this.onAnimationEnd(e)
}}
>
{this.renderImages()}
</ScrollView>
<View style={styles.pagingIndicatorStyle}>
{this.renderPagingIndicator()}
</View>
</View>
);
}
renderImages() {
let allImage = [];
for (let i = 0; i < imageData.length; i++) {
let item = imageData[i];
allImage.push(
<Image key={i} source={{uri: item}} style={styles.imageStyle}/>
);
}
return allImage;
}
onAnimationEnd(e) {
let offsetX = e.nativeEvent.contentOffset.x;
let pageIndex = Math.floor(offsetX / screenWidth);
this.setState({currentPage: pageIndex});
}
renderPagingIndicator() {
let indicatorArr = [];
let style;
for (let i = 0; i < imageData.length; i++) {
style = (i == this.state.currentPage) ? {color: 'orange'} : {color: 'white'};
indicatorArr.push(
<Text key={i} style={[{fontSize: 30}, style]}>
•
</Text>
);
}
return indicatorArr;
}
}
const styles = StyleSheet.create({
container: {
marginTop: 20,
backgroundColor: '#ffffff'
},
scrollViewStyle: {
backgroundColor: 'yellow',
},
imageStyle: {
width: screenWidth,
height:200,
},
pagingIndicatorStyle: {
height:25,
width:screenWidth,
backgroundColor:'rgba(0,0,0,0.4)',
position:'absolute',
bottom:0,
flexDirection:'row',
alignItems:'center',
justifyContent: 'center',
}
});
export default HorizontalScrollView;