feat: enhance TabLayout and HomeScreen with safe area insets and optimized refresh handling
This commit is contained in:
@@ -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={[
|
||||
|
||||
Reference in New Issue
Block a user