ReactNative开发——滑动组件
ReactNative开发——滑动组件环境window android react-native 0.45 ScrollView介绍ScrollView是一个可以滑动的组件,它内部可以是一个高度不受控制的View,但它自身必须要有个固定的高度。这里如果我们不给直接他设置高度,它的上层空间有固定高度的话也是可以的。
用法我们来看一下用法示例,大家可以直接copy我的代码运行试试看: /** * Created by blueberry on 6/9/2017. * @flow */
import React,{Component} from 'react';
import {
AppRegistry,StyleSheet,View,Text,ScrollView,ListView,FlatList,RefreshControl,Dimensions,Button,TextInput,} from 'react-native';
let totalWidth = Dimensions.get('window').width;
let totalHeight = Dimensions.get('window').height;
export default class MainPage extends Component {
state = {
isRefresh: false,}
_onRefresh() {
console.log('onRefresh.');
this.setState({isRefresh: true});
// 模拟获取数据需要三秒
setTimeout(() => this.setState({isRefresh: false}),3000);
}
_onScroll() {
console.log('onScroll.');
}
render() {
return (
<View style={styles.container}> <Button title="滑动到底部" onPress={() => _outScrollView.scrollToEnd({animated: false})}/> <ScrollView ref={(scrollView) => { _outScrollView = scrollView; }} contentContainerStyle={styles.outScrollView} onScroll={this._onScroll} //回调 scrollEventThrottle={100} // ios : 控制scroll回调的频率,没秒触发多少次 showsVerticalScrollIndicator={false} //设置不显示垂直的滚动条 keyboardDismissMode={'on-drag'} // 'none'默认值,滑动时不隐藏软件盘, // ‘on-drag'滑动时隐藏软件盘.interactive :ios可用。上滑可以回复键盘 keyboardShouldPersistTaps={'always'} //'never'默认值,点击TextInput以外的组件,软键盘收起, // 'always'不会收起,`handle` 当点击事件被子组件捕获时, //键盘不会自动收起,但我用android测试了,发现没有效果 //我使用的版本:RectNative 0.45 refreshControl={ <RefreshControl refreshing={this.state.isRefresh} onRefresh={this._onRefresh.bind(this)} title={'load...'} tintColor={'#ff0000'} colors={['#ff0000', '#00ff00','#0000ff']} progressBackgroundColor={'#ffff00'} /> } > <ScrollView horizontal={true} contentContainerStyle={styles.inScrollView} showsHorizontalScrollIndicator={false} //不显示滑动条 > <TextInput placeholder={'测试软键盘'} style={{width: totalWidth,height: 0.5 * totalHeight,backgroundColor: '#fff1ae'}}/> <View style={{width: totalWidth,backgroundColor: 'blue'}}/> </ScrollView> <ScrollView horizontal={true} contentContainerStyle={styles.inScrollView}> <TextInput placeholder={'测试软键盘'} style={{width: totalWidth,backgroundColor: 'blue'}}/> </ScrollView> <ScrollView horizontal={true} contentContainerStyle={styles.inScrollView}> <View style={{width: totalWidth,backgroundColor: 'red'}}/> <View style={{width: totalWidth,backgroundColor: 'blue'}}/> </ScrollView> <ScrollView horizontal={false} contentContainerStyle={styles.inScrollView}> <View style={{width: totalWidth,backgroundColor: 'blue'}}/> </ScrollView> </ScrollView> </View> ); } } var styles = StyleSheet.create({ container: { flex: 1,height: '50%',backgroundColor: 'grey',},outScrollView: { // flex: 1,这里指定flex的话,会出现不能上下滑动,原因在这样会把 "内容高度定死了",所以最好不要设置高度/flex,让内容的高度自适应 justifyContent: 'center',backgroundColor: 'green',inScrollView: { padding: 20,backgroundColor: '#88ff73' } }); AppRegistry .registerComponent( 'Project08',() => MainPage ) ;
上面的代码创建了一个 基本属性
ok,这些是基本属性,更多属性大家可以参考:http://reactnative.cn/docs/0.45/scrollview.html#content RefreshControl这个组件我上文的代码中,大家应该已经看到用法了。 refreshControl={
<RefreshControl refreshing={this.state.isRefresh} onRefresh={this._onRefresh.bind(this)} title={'load...'} tintColor={'#ff0000'} colors={['#ff0000','#0000ff']} progressBackgroundColor={'#ffff00'} /> }
需要的属性基本我都写上了,这里我再列个表格解释一下好了。
ListViewListView是一个可以垂直滑动的组件,一般用来显示列表数据 用法/** * Created by blueberry on 6/9/2017. * @flow */
import React,{Component} from 'react';
import {AppRegistry,Button} from 'react-native';
import StaticContainer from './StaticContainer';
let array = [];
{
let len = 100;
for (let i = 0; i < len; i++) {
array.push('测试数据' + i);
}
}
/** * 加个log,用来测试,是否更新。 */
class LogView extends Component {
componentDidUpdate() {
console.log(this.props.name + 'Did update');
}
render() {
return (
<Text style={{backgroundColor: '#ffd98c'}}> 我是:{this.props.name} </Text> ); } } export default class ListViewPage extends Component { constructor() { super(); let ds = new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2}); this.state = { //填充数据 dataSource: ds.cloneWithRows(array),}; } render() { return ( <ListView // 数据源 dataSource={this.state.dataSource} initialListSize={10} //初始的时候显示的数量 onChangeVisibleRows={(visible, changedRows) => { // 我用android测试,没有回调.... // visible: 类型:{ sectionID: { rowID: true }} // { sectionID: { rowID: true | false }} console.log('visible:' + JSON.stringify(visible)); console.log('changedRow:' + JSON.stringify(changedRows)); }} onEndReached={() => console.log('onEndReached')}//当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足 // onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时, // 如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。 onEndReachedThreshold={2} //调用onEndReached之前的临界值,单位是像素 pageSize={3} //每次渲染的行数 // 返回一个头部可以渲染的组件 renderHeader={() => ( <LogView name="header"/> )} //返回一个尾部可以渲染的组件 renderFooter={() => ( <StaticContainer> <LogView name="Footer"/> </StaticContainer> )} //显示每一行 renderRow={ (rowData,sectionID,rowID,highlightRow) => { return ( <Text style={{borderBottomColor: 'grey',borderBottomWidth: 1}}> {'rowData:' + rowData + ' sectionId:' + sectionID + " rowId:" + rowID + " highlightRow:" + highlightRow} </Text> ) }}/> ); } } AppRegistry.registerComponent('Project08',() => ListViewPage);
上面的代码实现了一个用来显示100条数据的列表,它还有一个头部,和一个尾部,因为头部和尾部的数据一般都不收布局变化,所有使用了一个 ListView.DataSourceListView.DataSource 主要用来为ListView提供数据,它的一般用法。上面的代码已经给出了。 let ds = new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2});
this.state = {
//填充数据
dataSource: ds.cloneWithRows(array),};
它还有另外一个方法: 基本属性
额,还有ScrollView有的属性,ListView都有;所有horizontal、refreshControl,都可以个ListView设置。 分组显示/** * Created by blueberry on 6/9/2017. * * @flow */
import React,Text} from 'react-native';
let array: Array<Array<string>> = [];
{
for (let i = 0; i < 10; i++) {
let group: Array<string> = [];
for (let j = 0; j < 10; j++) {
group.push('分组:' + i + " item:" + j);
}
array['分组' + i] = group;
}
}
export default class GroupListView extends Component {
constructor() {
super();
var ds = new ListView.DataSource({
rowHasChanged: (r1,r2) => r1 !== r2,sectionHeaderHasChanged: (pre,next) => pre !== next,});
this.state = {
/** * 填充数据 * @params 所有的分组数据,结构{分组1:[分组1 item1,分组1item2. ...],分组2:[分组2item1,....]} * @param sectionIdentities 每个分组的索引 */
dataSource: ds.cloneWithRowsAndSections(array,Object.keys(array)),};
}
render() {
return (
<ListView dataSource={this.state.dataSource} renderRow={(rowData) => { return <Text>{rowData}</Text>;
}}
renderSectionHeader={(sectionData,sectionId) => {
console.log('sectionData:' + JSON.stringify(sectionData) + ',sectionID:' + JSON.stringify(sectionId));
return <Text style={{backgroundColor: 'red'}}>{sectionData[0]}</Text> }} stickySectionHeadersEnabled={true} //开启之后,会有个粘性效果, stickyHeaderIndices={[1]} //一个子视图下标的数组(这个下标连section也算在内的,),用于决定哪些成员会在滚动之后固定在屏幕顶端.根 // stickySectionHeadersEnabled的效果很像 scrollRenderAheadDistance={10} //当一个行接近屏幕范围多少像素之内的时候,就开始渲染这一行。 /> ); } } AppRegistry.registerComponent('Project08',() => GroupListView);
上面代码实现了用listView分组显示item。 FlatListFlatList是ListView的升级版,它的性能比ListView好一些,但它目前刚出来,冒死还有些坑存在。。。 用法/** * Created by blueberry on 6/11/2017. */
import React,{Component,PureComponent} from 'react';
import {AppRegistry,TouchableOpacity} from 'react-native';
class ListItem extends PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
}
render() {
let color = this.props.selected ? 'red' : 'blue';
return (
<TouchableOpacity style={{height: 200,justifyContent: 'center',flex: 1,alignItems: 'center',backgroundColor: color} } onPress={this._onPress}> <Text style={{fontSize: 20,height: 100,}}>{this.props.title}</Text> <Text style={{fontSize: 18,height: 80}}>{this.props.content}</Text> </TouchableOpacity> ); } } /** * PureComponent 可以提高性能,只有在props或state发生改变时render。 */ export default class FlatListPage extends PureComponent { state = {selected: (new Map(): Map<string, boolean>)}; _onPressItem = (id: string) => { this.setState((state) => { const selected = new Map(state.selected); selected.set(id,!selected.get(id));//toggle. return {selected}; }); }; _keyExtractor = (item,index) => item.id; /** * 使用箭头函数,既保证了this指向FlatListPage,也保证了不会每次都生成一个新的函数,这样在对比prop时,就返回'没有改变' */ _renderItem = ({item}) => ( <ListItem id={item.id} onPressItem={this._onPressItem} selected={!!this.state.selected.get(item.id)} title={item.title} content={item.content} /> ); render() { return ( <FlatList data={this.props.data} renderItem={this._renderItem} // extraData={this.state} keyExtractor={this._keyExtractor} ItemSeparatorComponent={() => <View style={{height: 2,backgroundColor: 'black'}}/>} //分割线 ListFooterComponent={() => <View style={{height: 50,backgroundColor: 'red'}}/>} //尾部布局 ListHeaderComponent={() => <View style={{height: 50,backgroundColor: 'blue'}}/>} //头部布局 columnWrapperStyle={{height: 200,}} numColumns={2} // //getItemCount={40} //getItemLayout={(data,index) => ({length: 200,offset: 200 * index,index})} refreshing={false} onEndReachedThreshold={20} //决定距离底部20个单位的时候,回到onEndReacted,但是我这只20, // 他距离4000左右的时候就回掉了,测试版本Android reactNative Api:0.45 onEndReached={(info) => { console.log('onEndReacted:' + info.distanceFromEnd); }} /> ); } } { let array = []; for (let i = 0; i < 40; i++) { array[i] = {id: i,key: 'key' + i,title: '标题' + i,content: '内容' + i,}; } FlatListPage.defaultProps = {data: array}; } AppRegistry.registerComponent('Project08',() => FlatListPage);
常用属性
更多属性请参考: http://reactnative.cn/docs/0.45/flatlist.html#content 上述代码定义的组件都继承了 PureComponent,这个组件的作用是,只有prop和state它才render。实现它是为了提高效率。 SectionList是一个高性能的分组列表组件 使用/** * Created by blueberry on 6/12/2017. */
import React,SectionList,RefreshControl} from 'react-native';
class ListItem extends PureComponent {
render() {
return (
<Text style={{backgroundColor: 'red',height: 100}}>{this.props.title}</Text> ); } } let sections = []; for (let i = 0; i < 10; i++) { data = []; for (let j = 0; j < 10; j++) { data[j] = {title: '分组' + i + ',item' + j,id: j}; } sections.push({data: data,key: '分组' + i}); // 也可以使用下面方式自定义 不同section渲染不同类型的子组件 //sections.push({data: data,key: '分组' + i,renderItem: i === 2 ? ()=><ListItem title="测试"/> : undefined}); } export default class SectionListPage extends PureComponent { //为每一行生成唯一的key _keyExtractor = (item,index) => '' + item.key + index; render() { console.log(JSON.stringify(sections)); return ( <SectionList //渲染item的组件 renderItem={({item}) => <ListItem title={item.title} /> } //渲染sectionHeader的组件 renderSectionHeader={({section}) => <Text>{section.key}</Text> } //数据 sections={sections} //生成唯一的key keyExtractor={this._keyExtractor} ItemSeparatorComponent={() => <View style={{height: 2,backgroundColor: 'blue'}}/>} //头部布局 /> ); } } AppRegistry.registerComponent('Project08',() => SectionListPage);
基本属性
其余属性和 我在上述代码中有这么一行,用来设置不同的renderItem函数,读者可以去掉注释看看效果 总结其实我们文章中我们主要提到了 6个组件: 上面就是本文介绍的四个滑动组件,他们都支持下拉刷新组件,(ScrollView)有的属性,其他滑动组件基本都有。 ok,介绍到这里了,其中我写的测试源码,在上文都贴出来了,大家可以测试测试。 参考ReactNative 官网:http://facebook.github.io/react-native/releases/0.43/docs/flatlist.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |