React-Native仿某电商商品详情页面

本文介绍了使用React-Native模仿某电商商品详情页面的滑动效果,分为两种实现方式:一是利用rn手势监听Scrollview事件;二是封装原生组件。详细讲述了每种方式的实现思路,并提供了部分关键代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言: 一周又过去了,一直在赶需求,除了自己利用空余时间学习一下外压根就没时间去研究新东西,唉~程序猿就是这样,活到老学到老!! 废话不多说了,公司产品觉得某电商的商品详情页面很nice,问我们能不能实现(宝宝心里苦),于是研究了一波,下面把我研究的东西分享一下,小伙伴有啥好的实现方式还谢谢分享一下哦~拜谢!

先看一下最终实现的效果:
ios/android

这里写图片描述

简单来说就是分为两个部分(上下),两个都是(scrollview、flatlist)等滑动组件,第一个scrollview滑动到底部的时候,继续上拉显示第二个scrollview,第二个scrollview下拉到顶部的时候,继续下拉回到第一个scrollview并且第一个scrollview回到顶部.

下面说一下我的大体思路:

第一种方式:
利用rn手势,然后监听scrollview的滑动事件,我们都知道rn中的事件传递都是从父控件一层一层往下传递,所以父控件能够拦截scrollview也就是子控件的能力,当scrollview滑动到底部或者顶部的时候拦截scrollview的事件,把事件给父控件,然后通过控制父控件的垂直偏移量首先分页功能,说了那么多理论的东西小伙伴估计都累了,我们后面结合代码一起来说一下.

第二种方式:
封装一个native的组件实现上拉和下拉的操作,rn只需要做一些简单的监听就可以.

两种方式对比来看,能用rn实现最好,因为rn存在的目的也就是为了实现跨平台目的,都用native实现了还用rn干嘛!! 话虽然这样说,但是rn还是给开发人员提供了自定义的方法,用第二种方式实现有点就是性能和体验上要优于rn实现,我接下来会结合两种方式来实现.

先说一下第一种方式

第一步(把页面分为上下两部分):

render() {
        return (
            <View
                style={[styles.container]}
            >
                {/*第一部分*/}
                <Animated.View
                    style={[styles.container1,{
     
                        marginTop:this._aniBack.interpolate({
                            inputRange:[0,1],
                            outputRange:[0,-SCREEN_H],
                        })
                    }]}
                    {
    ...this._panResponder.panHandlers}
                >
                    <Animated.View
                        ref={(ref) => this._container1 = ref}
                        style={
   {
   width: SCREEN_W, height: SCREEN_H,
                            marginTop:this._aniBack1.interpolate({
                                inputRange:[0,1],
                                outputRange:[0,-100],
                            })}}
                    >
                        <ScrollView
                            ref={(ref)=>this._scroll1=ref}
                            bounces={false}
                            scrollEventThrottle={10}
                            onScroll={this._onScroll.bind(this)}
                            overScrollMode={'never'}
                        >
                            {this._getContent()}
                        </ScrollView>
                    </Animated.View>
                    <View style={
   {
   width:SCREEN_W,height:100,backgroundColor:'white',alignItems:'center',justifyContent:'center'}}>
                        <Text>上拉查看详情</Text>
                    </View>
                </Animated.View>

                {/*第二部分*/}
                <View
                    style={styles.container2}
                      {
    ...this._panResponder2.panHandlers}
                >
                    <Animated.View
                        ref={(ref) => this._container2 = ref}
                        style={
   {
                            width:SCREEN_W,height:100,backgroundColor:'white',alignItems:'center',justifyContent:'center',
                            marginTop:this._aniBack2.interpolate({
                                inputRange:[0,1],
                                outputRange:[-100,0],
                            })
                        }}
                    >
                        <Text>下拉回到顶部</Text>
                    </Animated.View>
                    <View
                        style={
   {
   width: SCREEN_W, height: SCREEN_H,}}
                    >
                        <ScrollView
                            ref={(ref)=>this._scroll2=ref}
                            bounces={false}
                            scrollEventThrottle={10}
                            onScroll={this._onScroll2.bind(this)}
                            overScrollMode={'never'}
                        >
                            {this._getContent()}
                        </ScrollView>
                    </View>
                </View>
            </View>
        );
    }

代码我待会会贴出来,原理很简单,我大体说一下我的实现思路,运行代码你会发现,页面是显示了一个红色页面(也就是上部分).

这里写图片描述

让我们把第一个页面的marginTop调为-SCREEN_H(屏幕高度)的时候,我们会看到第二屏蓝色页面
这里写图片描述

所以我们只需要在第一个红色页面的scrollview滑动到底部的时候,然后拦截事件,手指抬起的时候,让第一个页面的marginTop从(0到-屏幕高度)的转变,我们同时给个动画实现.那么问题来了,我们该怎么监听scrollview到达顶部或者底部呢?我们又该怎么拦截scrollview的事件呢?

监听scrollview到达顶部或者底部:

到达顶部我们都知道,当scrollview的y轴偏移量=0的时候我们就认为scrollview到达顶部了,转为代码就是:

  _onScroll2(event){
        this._reachEnd2=false;
        let y = event.nativeEvent.contentOffset.y;
        if(y<=0){
        //到达顶部了
            this._reachEnd2=true;
        }
    }

到达底部也就是当(子控件的高度=y轴滑动的距离+父控件的高度)的时候,转为代码为:

  _onScroll(event){
        this._reachEnd1=false;
        let y = event.nativeEvent.contentOffset.y;
        let height = event.nativeEvent.layoutMeasurement.height;
        let contentHeight = event.nativeEvent.contentSize.height;
        if (contentHeight > height && (y + height >= contentHeight)) {
        //到达顶部了
            this._reachEnd1=true;
        }
    }

父控件拦截子控件的事件:
我们在onMoveShouldSetPanResponderCapture返回true,父控件就是拦截掉滑动事件,然后交给自己处理(onPanResponderMove),那么我们红色页面(也就是第一页)的scrollview到达底部的时候,再往上拉的时候,我们拦截事件

 _handleMoveShouldSetPanResponderCapture(event: Object, gestureState: Object,): boolean {
        console.log('_handleMoveShouldSetPanResponderCapture');
        console.log(gestureState.dy);
        //当滑动到底部并且继续往上拉的时候
        return this._reachEnd1&&gestureState.dy<0;
    }

我们第二个页面(也就是蓝色页面)当scrollview滑动到顶部并且继续往下拉的时候,拦截事件:

   _handleMoveShouldSetPanResponderCapture2(event: Object, gestureState: Object,): boolean {
          console.log(gestureState.dy);
          console.log('_handleMoveShouldSetPanResponderCapture2');
          //当滑动到顶部并且继续往下拉的时候
        return this._reachEnd2&&gestureState.dy>=0;
    }

好啦~我们第一个页面的父控件拿到滑动事件后,我们继续往上拉,也就是把往上拉的距离赋给我们的“上拉查看详情“组件了:
_handlePanResponderMove(event: Object, gestureState: Object): void {
//防止事件拦截不准,我们把scrollview的scrollEnabled:false设置为false
this._scroll1.setNativeProps({
scrollEnabled:false
})
let nowLeft =gestureState.dy*0.5;
//控制一个页面的“上拉查看详情“组件显示
this._container1.setNativeProps({
marginTop:nowLeft
})
console.log(‘_handlePanResponderMove’,gestureState.dy);

  <Animated.View
                        ref={(ref) => this._container1 = ref}
                        style={
   {
   width: SCREEN_W, height: SCREEN_H,
                            marginTop:this._aniBack1.interpolate({
                                inputRange:[0,1],
                                outputRange:[0,-100],
                            })}}
                    >
                        <ScrollView
                            ref={(ref)=>this._scroll1=ref}
                            bounces={false}
                            scrollEventThrottle={10}
                            onScroll={this._onScroll.bind(this)}
                            overScrollMode={'never'}
                        >
                            {this._getContent()}
                        </ScrollView>
                    </Animated.View>
                    <View style={
   {
   width:SCREEN_W,height:100,backgroundColor:'white',alignItems:'center',justifyContent:'center'}}>
                        <Text>上拉查看详情</Text>
                    </View>

代码很简单,我就不一一解

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值