feat(tabbar): add onTabItemPress event and enhance TabBar functionality
- Introduced onTabItemPress event in TabBarRootView to handle tab item presses. - Updated TabBarModule to include the new event in the definition. - Modified TabBarRootWrapper to accept onTabItemPress and selectedIndex props. - Enhanced TabRoot to utilize the onTabItemPress callback for scroll-to-top functionality. This update improves user interaction with the tab bar by allowing for additional actions on tab item presses. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
a9d5cbd519
commit
a350950672
|
|
@ -9,29 +9,29 @@ import ExpoModulesCore
|
|||
|
||||
public class TabBarModule: Module {
|
||||
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("TabBarRoot")
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("TabBarRoot")
|
||||
|
||||
Function("switchTab") { [weak self] (reactTag: Int, index: Int) in
|
||||
DispatchQueue.main.async {
|
||||
guard let bridge = self?.appContext?.reactBridge else {
|
||||
return
|
||||
}
|
||||
|
||||
if let sourceView = bridge.uiManager.view(forReactTag: NSNumber(value: reactTag)) as! TabBarRootView?
|
||||
|
||||
{
|
||||
sourceView.switchToTab(index: index)
|
||||
}
|
||||
}
|
||||
Function("switchTab") { [weak self] (reactTag: Int, index: Int) in
|
||||
DispatchQueue.main.async {
|
||||
guard let bridge = self?.appContext?.reactBridge else {
|
||||
return
|
||||
}
|
||||
|
||||
View(TabBarRootView.self) {
|
||||
Prop("selectedIndex") { (view, index: Int) in
|
||||
view.switchToTab(index: index)
|
||||
}
|
||||
|
||||
Events("onTabIndexChange")
|
||||
if let sourceView = bridge.uiManager.view(forReactTag: NSNumber(value: reactTag))
|
||||
as! TabBarRootView?
|
||||
{
|
||||
sourceView.switchToTab(index: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View(TabBarRootView.self) {
|
||||
Prop("selectedIndex") { (view, index: Int) in
|
||||
view.switchToTab(index: index)
|
||||
}
|
||||
|
||||
Events("onTabIndexChange", "onTabItemPress")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class TabBarRootView: ExpoView {
|
|||
private var tabViewControllers: [UIViewController] = []
|
||||
|
||||
private let onTabIndexChange = EventDispatcher()
|
||||
private let onTabItemPress = EventDispatcher()
|
||||
|
||||
required init(appContext: AppContext? = nil) {
|
||||
super.init(appContext: appContext)
|
||||
|
|
@ -133,6 +134,14 @@ class TabBarRootView: ExpoView {
|
|||
// MARK: - UITabBarControllerDelegate
|
||||
|
||||
extension TabBarRootView: UITabBarControllerDelegate {
|
||||
func tabBarController(
|
||||
_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController
|
||||
) -> Bool {
|
||||
if let index = tabViewControllers.firstIndex(of: viewController) {
|
||||
onTabItemPress(["index": index, "currentIndex": tabBarController.selectedIndex])
|
||||
}
|
||||
return true
|
||||
}
|
||||
func tabBarController(
|
||||
_ tabBarController: UITabBarController, didSelect viewController: UIViewController
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useTypeScriptHappyCallback } from "@follow/hooks"
|
||||
import { useAtom } from "jotai"
|
||||
import type { FC, PropsWithChildren } from "react"
|
||||
import * as React from "react"
|
||||
import { use, useCallback, useMemo } from "react"
|
||||
import { StyleSheet } from "react-native"
|
||||
|
||||
import { useNavigationScrollToTop } from "@/src/components/layouts/tabbar/hooks"
|
||||
|
||||
import { BottomTabContext } from "./BottomTabContext"
|
||||
import { TabBarRootWrapper } from "./native"
|
||||
import { TabScreen } from "./TabScreen"
|
||||
|
|
@ -13,6 +16,8 @@ export const TabRoot: FC<PropsWithChildren> = ({ children }) => {
|
|||
const { currentIndexAtom } = use(BottomTabContext)
|
||||
const [tabIndex, setTabIndex] = useAtom(currentIndexAtom)
|
||||
|
||||
const scrollToTop = useNavigationScrollToTop()
|
||||
|
||||
const MapChildren = useMemo(() => {
|
||||
let cnt = 0
|
||||
return React.Children.map(children, (child) => {
|
||||
|
|
@ -33,6 +38,15 @@ export const TabRoot: FC<PropsWithChildren> = ({ children }) => {
|
|||
},
|
||||
[setTabIndex],
|
||||
)}
|
||||
onTabItemPress={useTypeScriptHappyCallback(
|
||||
(e) => {
|
||||
const { index, currentIndex } = e.nativeEvent
|
||||
if (index === currentIndex) {
|
||||
scrollToTop()
|
||||
}
|
||||
},
|
||||
[scrollToTop],
|
||||
)}
|
||||
selectedIndex={tabIndex}
|
||||
>
|
||||
{MapChildren}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ export const TabScreenWrapper = ({ title, icon, activeIcon, ...rest }: TabScreen
|
|||
return <View {...rest} />
|
||||
}
|
||||
|
||||
export const TabBarRootWrapper = (props: TabBarRootWrapperProps) => {
|
||||
export const TabBarRootWrapper = ({
|
||||
onTabIndexChange,
|
||||
onTabItemPress,
|
||||
selectedIndex,
|
||||
...props
|
||||
}: TabBarRootWrapperProps) => {
|
||||
return <View {...props} />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,16 @@ export interface ResolvedTabScreenProps extends Omit<TabScreenProps, "icon" | "a
|
|||
icon: (props: TabbarIconProps) => React.ReactNode
|
||||
}
|
||||
|
||||
export type TabBarRootWrapperProps = {
|
||||
export interface TabBarRootWrapperProps extends ViewProps {
|
||||
/**
|
||||
*
|
||||
* iOS only
|
||||
*/
|
||||
onTabIndexChange: (e: NativeSyntheticEvent<{ index: number }>) => void
|
||||
/**
|
||||
* iOS only
|
||||
*/
|
||||
onTabItemPress?: (e: NativeSyntheticEvent<{ index: number; currentIndex: number }>) => void
|
||||
|
||||
selectedIndex: number
|
||||
} & ViewProps
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue