feat: enhance TabLayout and HomeScreen with safe area insets and optimized refresh handling

This commit is contained in:
imeepos
2026-01-26 18:36:18 +08:00
parent 818f6e8591
commit 65b61ce05e
3 changed files with 55 additions and 11 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react'
import React, { useRef, useEffect, useCallback } from 'react'
import {
View,
Text,
@@ -6,9 +6,15 @@ import {
ScrollView,
StyleSheet,
ViewStyle,
Dimensions,
LayoutChangeEvent,
} from 'react-native'
import { DownArrowIcon } from '@/components/icon'
const SCREEN_WIDTH = Dimensions.get('window').width
const ARROW_WIDTH = 48 // 箭头按钮宽度 (padding 8 * 2 + icon ~24 + marginLeft 8)
const HORIZONTAL_PADDING = 16
interface TabNavigationProps {
tabs: string[]
activeIndex: number
@@ -30,6 +36,42 @@ export function TabNavigation({
wrapperStyle,
onLayout,
}: TabNavigationProps): JSX.Element {
const scrollViewRef = useRef<ScrollView>(null)
const tabLayouts = useRef<{ x: number; width: number }[]>([])
// 计算可用的滚动区域宽度
const scrollAreaWidth = SCREEN_WIDTH - HORIZONTAL_PADDING * 2 - (showArrow ? ARROW_WIDTH : 0)
// 滚动到激活的 tab 使其居中
const scrollToActiveTab = useCallback((index: number) => {
const layout = tabLayouts.current[index]
if (!layout || !scrollViewRef.current) return
// 计算让 tab 居中需要的滚动位置
const tabCenter = layout.x + layout.width / 2
const scrollX = tabCenter - scrollAreaWidth / 2
scrollViewRef.current.scrollTo({
x: Math.max(0, scrollX),
animated: true,
})
}, [scrollAreaWidth])
// 当 activeIndex 变化时滚动
useEffect(() => {
// 延迟执行确保布局已完成
const timer = setTimeout(() => {
scrollToActiveTab(activeIndex)
}, 50)
return () => clearTimeout(timer)
}, [activeIndex, scrollToActiveTab])
// 记录每个 tab 的布局
const handleTabLayout = useCallback((index: number, event: LayoutChangeEvent) => {
const { x, width } = event.nativeEvent.layout
tabLayouts.current[index] = { x, width }
}, [])
return (
<View
testID="tab-navigation"
@@ -45,6 +87,7 @@ export function TabNavigation({
>
<View style={styles.tabsContainer}>
<ScrollView
ref={scrollViewRef}
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.tabsScrollContent}
@@ -55,6 +98,7 @@ export function TabNavigation({
testID={`tab-${index}`}
style={[styles.tab, activeIndex === index && styles.activeTab]}
onPress={() => onTabPress(index)}
onLayout={(e) => handleTabLayout(index, e)}
>
<Text
style={[