存储库已移至https://github.com/react-navigation/react-navigation/tree/main/main/packages/react-native-tab-view。请打开问题并在那里提取请求。
React Native的跨平台选项卡视图组件。使用Android&iOS上的react-native-pager-view以及Web,MacOS和Windows上的Panresponder实施。
要使用此库,您需要确保使用正确版本的React Native。如果您使用的是低于0.63的React本机版本,则需要在尝试使用此库之前升级该版本。
react-native-tab-view版本 | 必需的反应本机版本 |
|---|---|
2.xx | < 0.63 |
3.xx | >= 0.63 |
在项目根中打开终端并运行:
yarn add react-native-tab-view现在,如果您打算支持iOS和Android,我们需要安装react-native-pager-view 。
如果您使用的是Expo,请确保您获得库的兼容版本,请运行:
expo install react-native-pager-view如果您不使用博览会,请运行以下内容:
yarn add react-native-pager-view我们完成了!现在,您可以在设备/模拟器上构建并运行该应用程序。
import * as React from 'react' ;
import { View , useWindowDimensions } from 'react-native' ;
import { TabView , SceneMap } from 'react-native-tab-view' ;
const FirstRoute = ( ) => (
< View style = { { flex : 1 , backgroundColor : '#ff4081' } } />
) ;
const SecondRoute = ( ) => (
< View style = { { flex : 1 , backgroundColor : '#673ab7' } } />
) ;
const renderScene = SceneMap ( {
first : FirstRoute ,
second : SecondRoute ,
} ) ;
export default function TabViewExample ( ) {
const layout = useWindowDimensions ( ) ;
const [ index , setIndex ] = React . useState ( 0 ) ;
const [ routes ] = React . useState ( [
{ key : 'first' , title : 'First' } ,
{ key : 'second' , title : 'Second' } ,
] ) ;
return (
< TabView
navigationState = { { index , routes } }
renderScene = { renderScene }
onIndexChange = { setIndex }
initialLayout = { { width : layout . width } }
/>
) ;
}在零食上尝试此示例
该软件包导出一个TabView组件,该组件是您用来渲染Tab View的一个组件,而TabBar组件是默认的Tab bar实现。
TabView负责渲染和管理选项卡的容器组件。默认情况下遵循材料设计样式。
基本用法如下:
< TabView
navigationState = { { index , routes } }
onIndexChange = { setIndex }
renderScene = { SceneMap ( {
first : FirstRoute ,
second : SecondRoute ,
} ) }
/> navigationState ( required )标签视图的状态。该州应包含以下属性:
index :代表routes数组中活动路线索引的数字routes :包含用于渲染选项卡的路由对象列表的数组每个路由对象应包含以下属性:
key :识别路线的独特键(必需)title :在标签栏中显示路线的标题icon :在标签栏中显示路由的图标accessibilityLabel :“选项卡”按钮的可访问性标签testID :标签按钮的测试ID例子:
{
index : 1 ,
routes : [
{ key : 'music' , title : 'Music' } ,
{ key : 'albums' , title : 'Albums' } ,
{ key : 'recents' , title : 'Recents' } ,
{ key : 'purchased' , title : 'Purchased' } ,
]
} TabView是一个受控组件,这意味着需要通过onIndexChange回调更新index 。
onIndexChange ( required )在选项卡更改上调用的回调,将新选项卡的索引作为参数接收。导航状态在被调用时需要更新,否则更改将被删除。
renderScene ( required )回调将React元素返回到渲染作为标签的页面。接收包含路由的对象作为参数:
const renderScene = ( { route , jumpTo } ) => {
switch ( route . key ) {
case 'music' :
return < MusicRoute jumpTo = { jumpTo } /> ;
case 'albums' :
return < AlbumsRoute jumpTo = { jumpTo } /> ;
}
} ;您需要确保您的各个路线实现了shouldComponentUpdate以提高性能。为了使指定组件更容易,您可以使用SceneMap助手。
SceneMap采用route.key映射的对象。关键以反应组件并返回一个函数以与renderScene Prop一起使用。
import { SceneMap } from 'react-native-tab-view' ;
...
const renderScene = SceneMap ( {
music : MusicRoute ,
albums : AlbumsRoute ,
} ) ;以这种方式指定组件很容易,并且会照顾实现shouldComponentUpdate方法。
每个场景都会收到以下道具:
route :组件渲染的当前路线jumpTo :跳到其他选项卡的方法,采用route.key 。position :代表当前位置的动画节点jumpTo方法可用于编程导航到其他选项卡:
this . props . jumpTo ( 'albums' ) ;使用React.PureComponent优化了使用SceneMap呈现的所有场景,并且在父母的道具或状态更改时,请勿重新渲染。如果您需要更多地控制场景如何更新(例如,即使navigationState未更改即使触发重新渲染),请直接使用renderScene而不是使用SceneMap 。
重要:例如,不要将内联函数传递给SceneMap ,不要执行以下操作:
SceneMap ( {
first : ( ) => < FirstRoute foo = { this . props . foo } /> ,
second : SecondRoute ,
} ) ;始终在文件的顶级其他地方定义您的组件。如果通过内联功能,它将重新创建每个渲染的组件,这将导致整个路线卸载并重新启动所有更改。这对于性能非常糟糕,也会导致任何当地国家丢失。
如果您需要传递其他道具,请使用自定义renderScene函数:
const renderScene = ( { route } ) => {
switch ( route . key ) {
case 'first' :
return < FirstRoute foo = { this . props . foo } /> ;
case 'second' :
return < SecondRoute /> ;
default :
return null ;
}
} ; renderTabBar返回自定义反应元件的回调用作标签栏:
import { TabBar } from 'react-native-tab-view' ;
...
< TabView
renderTabBar = { props => < TabBar { ... props } /> }
. . .
/ >如果未指定此功能,则呈现默认的选项卡栏。您通过此道具自定义默认的选项卡栏,提供自己的选项卡栏,或完全禁用标签栏。
< TabView
renderTabBar = { ( ) => null }
. . .
/ > tabBarPosition标签栏的位置在标签视图中。可能的值是'top'和'bottom' 。默认为'top' 。
lazy将对象带有当前路线并返回布尔值以指示是否懒洋洋地渲染场景。
默认情况下,所有场景都呈现为提供平滑的滑动体验。但是,您可能需要推迟未关注场景的渲染,直到用户看到它们为止。要启用特定场景的懒惰渲染, true从getLazy返回该route :
< TabView
lazy = { ( { route } ) => route . name === 'Albums' }
. . .
/ >当您为屏幕启用懒惰渲染时,通常需要一些时间才能渲染。您可以使用renderLazyPlaceholder Prop来自定义用户在此短期内看到的内容。
您也可以通过布尔值来为所有场景延迟懒惰:
< TabView
lazy
/> lazyPreloadDistance启用lazy后,您可以指定使用此道具预装多少个相邻路线。此值默认为0 ,这意味着懒惰页面进入视口。
renderLazyPlaceholder回调将自定义React元素返回到尚未渲染的路线的渲染。接收一个包含路由作为参数的对象。还需要启用lazy道具。
这种视图通常仅显示一秒钟。保持轻巧。
默认情况下,这使得null 。
keyboardDismissMode字符串指示键盘是否因响应阻力手势而被解雇。可能的值是:
'auto' (默认值):索引更改时键盘被解散。'on-drag' :拖动开始时会忽略键盘。'none' :拖动不会解散键盘。 swipeEnabled布尔值指示是否启用滑动手势。默认情况下启用滑动手势。通过false将禁用滑动手势,但是用户仍然可以通过按TAB栏来切换选项卡。
animationEnabled更改选项卡时启用动画。默认情况下是真的。
onSwipeStart当滑动手势启动时称为回调,即用户触摸屏幕并将其移动。
onSwipeEnd当滑动手势结束时称为回调,即用户在滑动手势后从屏幕上抬起手指。
initialLayout包含屏幕的初始高度和宽度的对象。通过这将改善最初的渲染性能。对于大多数应用程序,这是一个很好的默认值:
< TabView
initialLayout = { { width : Dimensions . get ( 'window' ) . width } }
. . .
/ > sceneContainerStyle样式适用于视图包装每个屏幕。您可以将其传递给一些默认样式,例如溢出剪辑:
pagerStyle适用于Pager View包装所有场景的样式。
style适用于选项卡视图容器的样式。
TabBar材料设计主题标签栏。要自定义标签栏,您需要使用TabView的renderTabBar Prop渲染TabBar并传递其他道具。
例如,要自定义指示器颜色和标签栏背景颜色,您可以分别将indicatorStyle和style道具传递给TabBar :
const renderTabBar = props => (
< TabBar
{ ... props }
indicatorStyle = { { backgroundColor : 'white' } }
style = { { backgroundColor : 'pink' } }
/>
) ;
//...
return (
< TabView
renderTabBar = { renderTabBar }
. . .
/ >
);getLabelText使用当前路由的对象并返回选项卡的标签文本。默认情况下使用route.title 。
< TabBar
getLabelText = { ( { route } ) => route . title }
. . .
/ > getAccessible函数将对象带有当前路由,并返回布尔值,以指示是否将选项卡标记为accessible 。默认为true 。
getAccessibilityLabel使用当前路由的对象,并返回“选项卡”按钮的可访问性标签。使用route.accessibilityLabel默认情况下,如果指定了默认情况,则使用路由标题。
< TabBar
getAccessibilityLabel = { ( { route } ) => route . accessibilityLabel }
. . .
/ > getTestID使用当前路由的对象,并返回“选项卡”按钮的测试ID,以在测试中找到此选项卡按钮。默认情况下使用route.testID 。
< TabBar
getTestID = { ( { route } ) => route . testID }
. . .
/ > renderIcon将对象带有当前路由,重点状态和颜色的功能,并返回自定义反应元素以用作图标。
< TabBar
renderIcon = { ( { route , focused , color } ) => (
< Icon
name = { focused ? 'albums' : 'albums-outlined' }
color = { color }
/>
) }
. . .
/ > renderLabel具有当前路由,重点状态和颜色的对象的功能,并返回自定义反应元素以用作标签。
< TabBar
renderLabel = { ( { route , focused , color } ) => (
< Text style = { { color , margin : 8 } } >
{ route . title }
</ Text >
) }
. . .
/ > renderTabBarItem使用TabBarItemProps对象并返回自定义React元素以用作选项卡按钮的函数。
renderIndicator函数将对象带有当前路由并返回自定义反应元素,以用作选项卡指示器。
renderBadge函数将对象带有当前路由并返回自定义反应元素以用作徽章。
onTabPress函数可以在选项卡上执行。它接收到“按下”选项卡的场景,对于滚动到顶部之类的东西很有用。
默认情况下,TAB PRESS还切换“选项卡”。为了防止这种行为,您可以致电preventDefault :
< TabBar
onTabPress = { ( { route , preventDefault } ) => {
if ( route . key === 'home' ) {
preventDefault ( ) ;
// Do something else
}
} }
. . .
/ > onTabLongPress函数可以在Tab长按下执行
activeColor在“活动”选项卡中的图标定制颜色和标签。
inactiveColor图标的自定义颜色和标签在“无活动”选项卡中。
pressColor材料波纹的颜色(仅Android> = 5.0)。
pressOpacity不透明度按下标签(仅iOS和Android <5.0)。
scrollEnabled布尔值指示是否可以使标签栏滚动。
如果将scrollEnabled设置为true ,则还应在tabStyle中指定一个width以改进初始渲染。
bounces布尔值指示滚动时的标签栏是否弹跳。
tabStyle样式适用于标签栏中的单个标签项目。
默认情况下,所有选项卡项目都根据容器的宽度占据相同的预定宽度。如果您希望他们采用其原始宽度,则可以在tabStyle中指定width: 'auto' 。
indicatorStyle适用于活动指示器的样式。
indicatorContainerStyle适用于指示器的容器视图的样式。
labelStyle适用于标签项目标签的样式。
contentContainerStyle适用于内部容器的样式。
style适用于标签栏容器的样式。
gap定义选项卡之间的间距。
testID测试塔巴尔的ID。可用于滚动测试中的标签栏
如果要将TAB视图与React Navigation的导航系统集成在一起,例如希望能够使用navigation.navigate等导航到选项卡,则可以使用以下官方集成:
请注意,由于反应导航的局限性,React Navigation 4集成无法使用某些功能。例如,可以动态更改渲染选项卡。
每次索引更改时, renderScene函数都会调用。如果您的renderScene功能很昂贵,那么如果它们不依赖索引,并使用shouldComponentUpdate或React.memo ,这是一个好主意,将每个路线移至单独的组件,以防止不必要的重新订阅者。
例如,而不是:
const renderScene = ( { route } ) => {
switch ( route . key ) {
case 'home' :
return (
< View style = { styles . page } >
< Avatar />
< NewsFeed />
</ View >
) ;
default :
return null ;
}
} ;执行以下操作:
const renderScene = ( { route } ) => {
switch ( route . key ) {
case 'home' :
return < HomeComponent /> ;
default :
return null ;
}
} ;如果您使用的是类组件,则<HomeComponent />是PureComponent :
export default class HomeComponent extends React . PureComponent {
render ( ) {
return (
< View style = { styles . page } >
< Avatar />
< NewsFeed />
</ View >
) ;
}
}或者,用React.memo包装,如果您使用的功能组件:
function HomeComponent ( ) {
return (
< View style = { styles . page } >
< Avatar />
< NewsFeed />
</ View >
) ;
}
export default React . memo ( HomeComponent ) ;我们需要测量容器的宽度,因此需要等待,然后再在屏幕上呈现一些元素。如果您知道初始宽度,则可以将其传递给,我们不需要等待测量。在大多数情况下,这只是窗口宽度。
例如,将以下initialLayout传递到TabView :
const initialLayout = {
height : 0 ,
width : Dimensions . get ( 'window' ) . width ,
} ;TAB视图仍将对尺寸的变化做出反应,并进行相应调整以适应诸如方向变化之类的事物。
如果您有很多路线,尤其是图像,则可以将动画放在很多方面。相反,您可以渲染有限数量的路线。
例如,以下操作以在每一侧仅渲染2条路线:
const renderScene = ( { route } ) => {
if ( Math . abs ( index - routes . indexOf ( route ) ) > 2 ) {
return < View /> ;
}
return < MySceneComponent route = { route } /> ;
} ;将TabView嵌套在垂直ScrollView中,将禁用TabView内部呈现的FlatList组件中的优化。因此,如果可能的话,请避免这样做。
lazy和renderLazyPlaceholder道具根据需要渲染路线默认情况下禁用lazy选项,以提供更平滑的选项卡切换体验,但是您可以启用它并提供占位符组件,以获得更好的懒惰加载体验。仅当lazy能够通过渲染路线呈现时,才能提高初始负载性能。有关更多详细信息,请参考道具参考。
在开发过程中,您可以运行示例应用程序来测试更改。
确保您的代码通过打字稿和ESLINT。运行以下验证:
yarn typescript
yarn lint要解决格式错误,请运行以下内容:
yarn lint -- --fix请记住,如果可能的话,为您的更改添加测试。