From cdf0d72bdcf5f29faaa4da7cce29d7918fbc5d82 Mon Sep 17 00:00:00 2001 From: zimplexing Date: Wed, 13 Aug 2025 19:23:32 +0800 Subject: [PATCH] fix(ui): resolve status bar overlay issue across all screens Add SafeAreaProvider to root layout and implement proper safe area handling: - Wrap app in SafeAreaProvider in _layout.tsx - Update HomeScreen to use safe area insets for proper top padding - Fix SettingsScreen safe area handling for all device types - Update ResponsiveHeader to use SafeAreaContext instead of manual calculation This ensures content is not covered by the status bar on mobile and tablet devices while maintaining TV compatibility. --- app/_layout.tsx | 37 ++++++++++++---------- app/index.tsx | 2 +- app/settings.tsx | 8 +++-- components/navigation/ResponsiveHeader.tsx | 9 +++--- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/app/_layout.tsx b/app/_layout.tsx index 3763521..04d4571 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -5,6 +5,7 @@ import * as SplashScreen from "expo-splash-screen"; import { useEffect } from "react"; import { Platform, View, StyleSheet } from "react-native"; import Toast from "react-native-toast-message"; +import { SafeAreaProvider } from "react-native-safe-area-context"; import { useSettingsStore } from "@/stores/settingsStore"; import { useRemoteControlStore } from "@/stores/remoteControlStore"; @@ -76,23 +77,25 @@ export default function RootLayout() { } return ( - - - - - - {Platform.OS !== "web" && } - - - - - - - - - - - + + + + + + + {Platform.OS !== "web" && } + + + + + + + + + + + + ); } diff --git a/app/index.tsx b/app/index.tsx index 2df7da2..a1e25de 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -187,7 +187,7 @@ export default function HomeScreen() { const dynamicStyles = StyleSheet.create({ container: { flex: 1, - paddingTop: deviceType === "mobile" ? 0 : 40, + paddingTop: deviceType === "mobile" ? insets.top : deviceType === "tablet" ? insets.top + 20 : 40, }, headerContainer: { flexDirection: "row", diff --git a/app/settings.tsx b/app/settings.tsx index e57052d..145a53e 100644 --- a/app/settings.tsx +++ b/app/settings.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { View, StyleSheet, FlatList, Alert, KeyboardAvoidingView, Platform } from "react-native"; import { useTVEventHandler } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; import { ThemedText } from "@/components/ThemedText"; import { ThemedView } from "@/components/ThemedView"; import { StyledButton } from "@/components/StyledButton"; @@ -24,6 +25,7 @@ export default function SettingsScreen() { const { loadSettings, saveSettings, setApiBaseUrl, setM3uUrl } = useSettingsStore(); const { lastMessage, targetPage, clearMessage } = useRemoteControlStore(); const backgroundColor = useThemeColor({}, "background"); + const insets = useSafeAreaInsets(); // 响应式布局配置 const responsiveConfig = useResponsiveLayout(); @@ -162,7 +164,7 @@ export default function SettingsScreen() { useTVEventHandler(deviceType === "tv" ? handleTVEvent : () => {}); // 动态样式 - const dynamicStyles = createResponsiveStyles(deviceType, spacing); + const dynamicStyles = createResponsiveStyles(deviceType, spacing, insets); const renderSettingsContent = () => ( @@ -214,7 +216,7 @@ export default function SettingsScreen() { ); } -const createResponsiveStyles = (deviceType: string, spacing: number) => { +const createResponsiveStyles = (deviceType: string, spacing: number, insets: any) => { const isMobile = deviceType === "mobile"; const isTablet = deviceType === "tablet"; const isTV = deviceType === "tv"; @@ -224,7 +226,7 @@ const createResponsiveStyles = (deviceType: string, spacing: number) => { container: { flex: 1, padding: spacing, - paddingTop: isTV ? spacing * 2 : 0, + paddingTop: isTV ? spacing * 2 : isMobile ? insets.top + spacing : insets.top + spacing * 1.5, }, header: { flexDirection: "row", diff --git a/components/navigation/ResponsiveHeader.tsx b/components/navigation/ResponsiveHeader.tsx index f8d8ba5..da856a9 100644 --- a/components/navigation/ResponsiveHeader.tsx +++ b/components/navigation/ResponsiveHeader.tsx @@ -5,6 +5,7 @@ import { ArrowLeft } from 'lucide-react-native'; import { ThemedText } from '@/components/ThemedText'; import { useResponsiveLayout } from '@/hooks/useResponsiveLayout'; import { DeviceUtils } from '@/utils/DeviceUtils'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; interface ResponsiveHeaderProps { title?: string; @@ -21,6 +22,7 @@ const ResponsiveHeader: React.FC = ({ }) => { const router = useRouter(); const { deviceType, spacing } = useResponsiveLayout(); + const insets = useSafeAreaInsets(); // TV端不显示Header,使用现有的页面内导航 if (deviceType === 'tv') { @@ -35,7 +37,7 @@ const ResponsiveHeader: React.FC = ({ } }; - const dynamicStyles = createStyles(spacing, deviceType); + const dynamicStyles = createStyles(spacing, deviceType, insets); return ( <> @@ -74,14 +76,13 @@ const ResponsiveHeader: React.FC = ({ ); }; -const createStyles = (spacing: number, deviceType: string) => { +const createStyles = (spacing: number, deviceType: string, insets: any) => { const minTouchTarget = DeviceUtils.getMinTouchTargetSize(); - const statusBarHeight = Platform.OS === 'ios' ? 44 : StatusBar.currentHeight || 24; return StyleSheet.create({ container: { backgroundColor: '#1c1c1e', - paddingTop: statusBarHeight, + paddingTop: insets.top, borderBottomWidth: 1, borderBottomColor: '#333', shadowColor: '#000',