react native开发Android 篇——ScrollView和ViewPagerAndroid实现滑动翻页功能

react native开发Android 篇——ScrollView和ViewPagerAndroid实现滑动翻页功能

详细代码可前往我在github上的demo查看。

ScrollView使用PanResponder实现滑动和点击翻页

  • onScrollBeginDrag
    当用户开始拖动此视图时调用此函数。

  • onScroll
    在滚动的过程中,每帧最多调用一次此回调函数。调用的频率可以用scrollEventThrottle属性来控制。

  • onScrollEndDrag
    当用户停止拖动此视图时调用此函数。

  • scrollTo
    滚动到指定的x, y偏移处。第三个参数为是否启用平滑滚动动画。还有一个duration参数则是仅限android可以使用的滚动持续时间。

  • 获取元素使用ref

ScrollView.nativeEvent返回的是一个对象,详细信息如下表所示:

属性Value
responderIgnoreScroll类型是Boolean,作用暂时未知
target类型是number,接收触摸事件的元素id
velocity类型是object,作用暂时未知eg:{ y: 0, x: 0 }
layoutMeasurementScrollView可视区域的大小,eg:{ height: 491, width: 360 }表示491是ScrollView的高度,360是屏幕的宽度
contentSizeScrollView的大小,eg:{ height: 491, width: 965 }
contentOffset用来手动设置初始的滚动坐标。默认值为{x: 0, y: 0}。eg:{ y: 0, x: 303 }表示y轴不变,x轴向右移动303
contentInset内容范围相对滚动视图边缘的坐标。默认为{top: 0, left: 0, bottom: 0, right: 0}。

注意:使用ScrollView自己的方法滚动会有惯性存在,可能会来回的滚动,所以在这里使用PanResponder完成页面的翻转。

使用:

import React, {Component} from 'react';
import {Image, StyleSheet, Text, View,TouchableHighlight,Animated,ScrollView,Dimensions,PanResponder,YellowBox} from 'react-native';
export default class App extends React.Component {
  constructor(props){
    super(props);
    this.state={
      pageArr:[require('../../src/images/1.jpg'),require('../../src/images/2.jpg'),require('../../src/images/3.jpg'),require('../../src/images/4.jpg'),require('../../src/images/5.jpg')],
      swiperIndex:0,
      screent_width:Dimensions.get('window').width,
      ScrollView_contentOffset_before:0,
      isLeft:false,
    }
    YellowBox.ignoreWarnings([//禁止componentWillMount和componentWillReceiveProps的黄色警告
      'Warning: componentWillMount is deprecated',
      'Warning: componentWillReceiveProps is deprecated',
    ]);
  }
  
  componentWillMount() {
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => {},
      onPanResponderGrant: (evt, gestureState) => {},
      onPanResponderStart: (evt, gestureState) => {},
      onPanResponderMove: (evt, gestureState) => {
        let isLeft=false;
        let touch_move=this.state.ScrollView_contentOffset_before;
        let flag=true;
        if (gestureState.dx > 0) {//右移
          isLeft=false;
          touch_move=touch_move-parseInt(gestureState.dx);
        } else {
          isLeft=true;
          touch_move=touch_move+parseInt(Math.abs(gestureState.dx));
        }
        flag=this.isMove(this.state.swiperIndex,isLeft);;
        if(flag){
          this.refs.swiper_ScrollView.scrollTo({ x:touch_move, y: 0, animated: true }, 1);
        }
        this.setState({
          isLeft:isLeft,
        })
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        let flag=this.isMove(this.state.swiperIndex,this.state.isLeft);
        if(flag){
          this.ScrollView_move(true,0);
        }
      },
      onPanResponderTerminate: (evt, gestureState) => {},
      onShouldBlockNativeResponder: (evt, gestureState) => {
        return true;
      },
    });
  }
  isMove(index,isLeft){
    let flag=true;
    if(index==0&&isLeft){//是第一页则可以向左滑
      flag=true;
    }else if(index==0&&!isLeft){//是第一页则不可以右滑
      flag=false;
    }
    if(index==this.state.pageArr.length-1&&isLeft){//是最后页则不能向左滑
      flag=false;
    }else if(index==this.state.pageArr.length-1&&!isLeft){//是第一页则可以右滑
      flag=true;
    }
    return flag;
  }
  
  ScrollView_move(isDrag,index){//isDrag为true是滑动,为false是点击
    var that = this;
    let { pageArr, isLeft,ScrollView_contentOffset_before,screent_width } = that.state;
    var swiperIndex=index;
    isLeft=isDrag?isLeft:swiperIndex>this.state.swiperIndex?true:false;
    var move_spacing= isLeft ? (screent_width) : (-screent_width);//每次移动多少
    var move_width=ScrollView_contentOffset_before+ move_spacing;//ScrollView移动的距离
   
    if(isDrag){
      swiperIndex=Math.abs(Math.floor(move_width / move_spacing));
    }else{//点击分页按钮
      move_width=ScrollView_contentOffset_before+ move_spacing*Math.abs(index-this.state.swiperIndex);
    }
    that.refs.swiper_ScrollView.scrollTo({ x: move_width, y: 0, animated: true }, 1);
    this.setState({
      ScrollView_contentOffset_before:move_width,
      swiperIndex:swiperIndex,
    })
  }
  render() {
    const {pageArr,swiperIndex,screent_width}=this.state;
    return (
      <View style={styles.container}>
        <View style={styles.swiperContainer}>
          <ScrollView  
            ref='swiper_ScrollView'
            horizontal={true}
            showsHorizontalScrollIndicator={false}
            {...this._panResponder.panHandlers}
            scrollEnabled={false}
          >
            {
              pageArr.map((item,index)=>{
                return (
                  <View style={[styles.pageItem,{width:screent_width}]} key={index}>
                    <Image style={styles.pageItemImg}  source={item}></Image>
                  </View>
                )
              })
            }
          </ScrollView>
          <View style={styles.pagination}>
            {
              pageArr.map((item,index)=>{
                return (
                  <TouchableHighlight
                    underlayColor='#fff'
                    onPress={this.ScrollView_move.bind(this,false,index)}
                    key={index} style={[styles.paginationItem,{backgroundColor:index==swiperIndex?"red":"#fff"}]}>
                    <Text></Text>
                  </TouchableHighlight>
                )
              })
            }
          </View>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container:{
    flex:1
  }
});

ViewPagerAndroid滑动翻页和使用setPage点击翻页

一个允许在子视图之间左右翻页的容器。每一个 ViewPagerAndroid 的子容器会被视作一个单独的页,并且会被拉伸填满 ViewPagerAndroid
注:所有的子视图都必须是纯 View,而不能是自定义的复合容器,ViewPagerAndroid必须设置大小,不然子视图内容不显示

安装:

yarn add @react-native-community/viewpager
react-native link @react-native-community/viewpager//react-native的版本小于0.60执行,否则跳过这步

常用属性和方法:
initialPage:初始选中的页的下标,类型是number
onPageSelected:在页面切换完成后(当用户在页面间滑动)调用,其中event.nativeEvent.position 是当前页的下标
setPage:用于ViewPager滚动到指定页面

使用:

import React, {Component} from 'react';
import {Image, StyleSheet, Text, View,TouchableHighlight} from 'react-native';
import ViewPager from "@react-native-community/viewpager";
export default class App extends React.Component {
  constructor(props){
    super(props);
    this.state={
      pageArr:[require('./src/images/1.jpg'),require('./src/images/2.jpg'),require('./src/images/3.jpg'),require('./src/images/4.jpg'),require('./src/images/5.jpg')],
      swiperIndex:0
    }
  }
  render() {
    const {pageArr,swiperIndex}=this.state;
    return (
      <View style={styles.container}>
        <View style={styles.swiperContainer}>
          <ViewPager style={styles.ViewPager}  initialPage={swiperIndex}
            ref='ViewPager'
            onPageSelected={(event)=>{
              this.setState({
                swiperIndex:event.nativeEvent.position 
              })
            }}
          >
            {
              pageArr.map((item,index)=>{
                return (
                  <View style={styles.pageItem} key={index}>
                    <Image style={styles.pageItemImg}  source={item}></Image>
                  </View>
                )
              })
            }
          </ViewPager>
          <View style={styles.pagination}>
            {
              pageArr.map((item,index)=>{
                return (
                  <TouchableHighlight
                    underlayColor='transparent'
                    onPress={()=>{
                      this.refs.ViewPager.setPage(index);//点击滚动到指定页
                      this.setState({
                        swiperIndex:index
                      })
                    }}
                    key={index} style={[styles.paginationItem,{backgroundColor:index==swiperIndex?"red":"#fff"}]}>
                    <Text></Text>
                  </TouchableHighlight>
                )
              })
            }
          </View>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container:{
    flex:1
  }
});

swiper_style.js文件的代码如下所示:

import React from 'react';
import {
StyleSheet
} from 'react-native';
const swiper_styles = StyleSheet.create({
    swiperContainer:{
      width:'100%',
      height:200,
      position:'relative',
    },
    ViewPager:{
      width:'100%',
      height:'100%',
    },
    pageItem:{
      width:'100%',
      height:'100%',
    },
    pageItemImg:{
      width:'100%',
      height:'100%'
    },
    pagination:{
      position:"absolute",
      bottom:10,
      zIndex:2,
      height:12,
      width:'100%',
      justifyContent:"center",
      flexDirection:"row",
      alignItems:"center",
    },
    paginationItem:{
      width:10,
      height:10,
      borderRadius:50,
      marginRight:10
    }
  });
  module.exports = swiper_styles;

运行结果:

这只是简单的翻页功能,有时间的话我会在写其他的,比如自动翻页、循环翻页等,至于啥时候写或者写完我也不知道,此处省略。。。。,不过对于完整的轮播图有为大神都给我搭好梯子了,拿来用就可以了,大神的轮播图使用

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native中,当一个ScrollView嵌套在另一个ScrollView中时,子ScrollView默认是不可以滑动的。为了让子ScrollView可以滑动,需要在父ScrollView的onTouchStart、onTouchMove和onTouchEnd事件中对事件进行处理。 具体来说,可以在父ScrollView的onTouchStart事件中记录下当前手指的位置,然后在onTouchMove事件中判断当前手指的位置是否在子ScrollView的范围内,如果是,则将事件交给子ScrollView处理;如果不是,则将事件交给父ScrollView处理。在onTouchEnd事件中,可以清除掉已经记录的手指位置信息。 以下是一个示例代码: ``` import React, { Component } from 'react'; import { ScrollView, View } from 'react-native'; class ParentScrollView extends Component { constructor(props) { super(props); this.state = { isChildScrolling: false, childScrollTop: 0, }; } handleChildScroll = (event) => { const { contentOffset } = event.nativeEvent; this.setState({ childScrollTop: contentOffset.y, }); } handleTouchStart = (event) => { const { locationY } = event.nativeEvent; if (locationY > this.state.childScrollTop) { this.setState({ isChildScrolling: true, }); } } handleTouchMove = (event) => { const { locationY } = event.nativeEvent; if (this.state.isChildScrolling) { this.childScrollView.scrollTo({ y: locationY - this.state.childScrollTop }); } } handleTouchEnd = () => { this.setState({ isChildScrolling: false, childScrollTop: 0, }); } render() { return ( <ScrollView onTouchStart={this.handleTouchStart} onTouchMove={this.handleTouchMove} onTouchEnd={this.handleTouchEnd} > <View style={{ height: 200 }}> <ScrollView ref={(ref) => { this.childScrollView = ref; }} onScroll={this.handleChildScroll} > {/* 子ScrollView的内容 */} </ScrollView> </View> {/* 父ScrollView的其他内容 */} </ScrollView> ); } } export default ParentScrollView; ``` 在上面的代码中,首先在父ScrollView的state中记录了一个isChildScrolling和childScrollTop变量,分别表示子ScrollView是否正在滑动,以及子ScrollView的当前scrollTop值。然后在父ScrollView的onTouchStart事件中,根据手指位置是否在子ScrollView的范围内,来判断是否将事件交给子ScrollView处理。在onTouchMove事件中,如果子ScrollView正在滑动,则通过scrollTo方法来滑动ScrollView。在onTouchEnd事件中,清除掉记录的变量信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值