我试图在底部选项卡导航器上方显示一个媒体播放器,就像在 Spotify 应用程序中一样。 它应该在所有屏幕(底部选项卡)上保持相同的状态。
有什么建议或方法可以在 React Native 中实现这一点吗?
我刚刚解决了这个问题
import { BottomTabBar } from '@react-navigation/bottom-tabs';
import SmallVideoPlay from 'YOUR_PATH_OF_THE_COMPONENT';
<Tab.Navigator
tabBar={(props) => (
<>
<SmallVideoPlay />
<BottomTabBar {...props} />
</>
)}
>
<Tab.Screen name="HomeStack" component={Home}/>
{/* .... */}
</Tab.Navigator/>
我建议使用 React.Context,因为您想在每个屏幕上显示具有相同状态的相同对象(音乐控制面板),而不是在每个屏幕上显示副本。
对于定位,我建议使用
absolute
位置。这与“react-navigation”一起使用,因为标题和底部区域发生了变化。
这意味着 bottom:0
不再是选项卡导航器中的屏幕底部,而是位于 TabBar 的正上方。
这是一个示例:
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { MusicControlPanelContext, MusicControlPanelConsumer } from './components/MusicControlContext';
import {MusicControlPanel} from './components/MusicContorlPanel'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<MusicControlPanelContext.Provider value={MusicControlPanel}>
<>
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: 'gray',
activeBackgroundColor: '#ff0000',
inactiveBackgroundColor: '#ff0000',
style: {
backgroundColor: '#ffffff',
},
}}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
</>
</MusicControlPanelContext.Provider>
);
}
import * as React from 'react';
import { MusicControlPanelContext } from './MusicControlPanelContext';
import { View } from 'react-native';
function MusicControlPanelConsumer() {
return (
<MusicControlPanelContext.Consumer>
{(Component) => <Component/>}
</MusicControlPanelContext.Consumer>
);
}
export { MusicControlPanelConsumer };
import * as React from 'react';
import {MusicControlPanel} from '../MusicContorlPanel'
export const MusicControlPanelContext = React.createContext<React.FC>(MusicControlPanel);
import * as React from 'react';
import { View, Text, Pressable } from 'react-native';
export const MusicControlPanel: React.FC = () => {
const [startStop, setStartStop] = React.useState(false);
return (
<View
style={{
position: 'absolute',
width: '90%',
height: 100,
backgroundColor: '#ff00ff',
bottom: 10,
justifyContent: 'center',
alignItems: 'center'
}}>
<Pressable
onPress={() =>
setStartStop((val) => {
return !val;
})
}>
<Text>{startStop ? 'Start' : 'Stop'}</Text>
</Pressable>
</View>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
您只需要计算底部导航栏的高度并创建一个位置为“绝对”的视图,并将其保持在底部导航栏上方,将导航栏的高度分配给该视图的“底部”。
<View>
<View
style={{
position: "absolute",
backgroundColor: "#4470AE",
bottom: 75,
flexDirection: "row",
width: "90%",
height: 60,
paddingVertical: "3%",
alignSelf: "center",
borderRadius: 12,
margin: "3%",
}}
></View>
<View
style={{
position: "absolute",
backgroundColor: "orange",
bottom: 0,
height: 75,
flexDirection: "row",
width: "100%",
justifyContent: "space-around",
paddingVertical: "3%",
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
}}
>
</View>
</View>
创建一个片段并将组件“FooterRadioPlayer”放置在Tab.Navigator的下方
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import FooterRadioPlayer from "../../FooterRadioPlayer"
const Tab = createBottomTabNavigator();
<>
<Tab.Navigator
initialRouteName="Home"
screenOptions={() => ({
headerShown: false,
tabBarActiveTintColor: "#000000",
tabBarInactiveTintColor: "#C4C4C4",
tabBarHideOnKeyboard: true,
})}
>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
tabBarIcon: ({ focused }) =>
!focused ? (
<HomeIcon style={{ width: 20, height: 20 }} />
) : (
<ActiveHomeIcon style={{ width: 20, height: 20 }} />
),
}}
/>
<Tab.Screen
name="Search"
component={SearchStackScreen}
options={{
tabBarIcon: ({ focused }) =>
!focused ? (
<SearchIcon style={{ width: 20, height: 20 }} />
) : (
<ActiveSearchIcon style={{ width: 20, height: 20 }} />
),
}}
/>
...
</Tab.Navigator>
<FooterRadioPlayer />
</>
然后在组件样式表中,将其与您的愿望对齐。
footerRadioPlayer: {
paddingHorizontal: 10,
width: "100%",
bottom: 55,
right: 0,
left: 0,
position: "absolute",
alignSelf: "center",
justifyContent: "center",
},
最终结果