React Native整体上下滑动的标签页(标签页嵌套,抖音-我-页面)

由于疫情影响,春节在家足足呆了快二十天了,葛优躺了几天后觉得还是得做点什么,于是想着把之前写的东西再总结下和学点新东西。
年前一段时间,RN项目需要用一个整体可以纵向滑动的标签页。网上没有找到让人满意的组件,于是打算自己封装一个,期间遇到了一些问题,后面算是能达到比较好的效果,并且兼容ios、android平台了,决定趁着这段空闲时间分享出来和大家一起探讨,共同进步。
大家可以直接点击跳转源码
组件名:react-native-head-tab-view

iOS效果图
demo_ios.gif

Android效果图:
demo_android.gif

开发思路:
由于是整体滑动的标签页,那首先得有一个标签页组件,我之前正好封装了一个,于是这个组件就在其基础上进行开发了,下面是我当时的一些思路。
我在设计之初,最先想到是用ScrollView包裹标签页,达到整体滑动的效果,但是会有诸多问题,列举一二,比如几个标签页高度不同,ScrollView必须能容纳最长的那个标签页,那从最长的标签页滑动到比较短的标签页时就会有白条,需要另外处理,比较消耗RN的性能;再就是顶部滑出屏幕和滑入屏幕时,需要在ScrollView和标签页直接切换手势,非常影响流畅性。
后面决定用动画去做这件事,转换思路后豁然开朗,至少性能可以达到原生级别。
接下来拆解需求,无非是要达到以下几个目的:

  • 标签页左右滑动功能正常,顶部加了一个头部Head组件。
  • 任何一个标签页滑动时,计算距离顶部的距离,决定Head组件的动画行为。
  • 共享不同标签页的垂直滑动距离,达到共同操控Head组件的目的
  • 兼容标签页下官方的所有滑动组件(ScrollView,FlatList,SectionList)

那只需要针对以上问题一一解决就可以了。

  • 首先问题一,需要加Head组件,那怎么加,加到哪里,可以看下面(左),标签页组件正常布局,只让所有标签页子页面加了个paddingTop,空出一个Head组件的位置。
    third.png
  • 问题二比较简单,计算滑动距离小于Head高度时,通过区间动画决定Head的轨迹。
  • 解决问题三只需要将记录Y轴位置的对象提升到更高一级,放在标签页组件中,然后下发到各个标签页子页面,由当前正在滚动的子页面去记录和维护这个对象。
  • 问题四的解决办法只需要封装一个高阶组件:接受当前使用的滑动组件,返回一个满足以上功能的新组件,也能同时达到封装内聚的目的。

补充几个点:

  1. 由于Tabbar初始位置在屏幕顶部,需要给它一个和滚动距离成反比的动画,也就是说初始位移值是Head的高度,到最后位移值是0,也就是回到原位置顶在顶部。(如下图)
    move.png
    滚动距离超出Head高度后:
    end.png

  2. 为了达到效果,我们在滚动标签Tab1页面时,是需要Tab2、Tab3也同时滚动的,那就会出现如果Tab2、Tab3未加载出数据,或者加载的数据少,不够滚动的情况。我采取的是通过动态计算,用占位高度去弥补的方式。

  3. 由于标签页子页面是用高阶组件HPageViewHoc包裹,我用了Ref转发,能通过ref直接取到被包裹住的那个组件,但是内部用了const AnimatePageView = Animated.createAnimatedComponent(WrappedComponent),你取到的ref会是一个动画对象,请再通过getNode()获取实际的FlatList组件,如下面代码。

import { HPageViewHoc } from 'react-native-viscous-tabview'
const HFlatList = HPageViewHoc(FlatList)

render() {
        const { data } = this.state;
        return (
            <HFlatList
                {...this.props}
                ref={_ref=>this.list=_ref}
                data={data}
                renderItem={this.renderItem.bind(this)}
                keyExtractor={(item, index) => index.toString()}
            />
        )
    }
handleRef(){
    this.list.getNode()...
}

如果大家有什么疑问可以在文章下方评论区留言,如果有bug请提在issues区

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于React Native的注册页面,你可以按照以下步骤进行开发: 1. 创建一个新的React Native项目:打开终端并运行以下命令: ``` npx react-native init MyRegistrationApp ``` 2. 进入项目目录: ``` cd MyRegistrationApp ``` 3. 在项目中安装依赖: ``` npm install ``` 4. 创建一个新的注册页面组件,例如`RegistrationScreen.js`。 5. 在`RegistrationScreen.js`中,导入所需的React Native组件: ```javascript import React, { useState } from 'react'; import { View, Text, TextInput, Button } from 'react-native'; ``` 6. 创建一个函数式组件`RegistrationScreen`,并设置初始状态变量来存储用户输入的数据: ```javascript const RegistrationScreen = () => { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); return ( <View> <Text>Registration Screen</Text> <TextInput placeholder="Name" value={name} onChangeText={(text) => setName(text)} /> <TextInput placeholder="Email" value={email} onChangeText={(text) => setEmail(text)} /> <TextInput placeholder="Password" secureTextEntry value={password} onChangeText={(text) => setPassword(text)} /> <Button title="Register" onPress={handleRegistration} /> </View> ); }; export default RegistrationScreen; ``` 7. 在`handleRegistration`函数中,你可以处理注册逻辑,例如向服务器发送注册请求等。 8. 在主App组件中导入`RegistrationScreen`组件并将其渲染在需要的位置: ```javascript import React from 'react'; import { View } from 'react-native'; import RegistrationScreen from './RegistrationScreen'; const App = () => { return ( <View> {/* 其他组件和内容 */} <RegistrationScreen /> </View> ); }; export default App; ``` 这样,你就创建了一个简单的React Native注册页面。你可以根据你的需求进行布局和样式的修改,并添加其他所需的功能。希望对你有帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值