Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove touch disabling in header corners #1157

Merged
merged 4 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import Test1072 from './src/Test1072';
import Test1084 from './src/Test1084';
import Test1091 from './src/Test1091';
import Test1096 from './src/Test1096';
import Test1157 from './src/Test1157';
import Test1162 from './src/Test1162';

export default function App() {
Expand Down
62 changes: 62 additions & 0 deletions TestsExample/src/Test1157.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react';
import {Button, View, TouchableOpacity} from 'react-native';
import {NavigationContainer, ParamListBase} from '@react-navigation/native';
import {createNativeStackNavigator, NativeStackNavigationProp} from 'react-native-screens/native-stack';

function First({
navigation,
}: {
navigation: NativeStackNavigationProp<ParamListBase>;
}) {
return (
<View style={{flex: 1, backgroundColor: 'red'}}>
<Button
title="Tap me for second screen"
onPress={() => navigation.navigate('Second')}
/>
</View>
);
}

function Second({
navigation,
}: {
navigation: NativeStackNavigationProp<ParamListBase>;
}) {
return (
<View style={{flex: 1, backgroundColor: 'yellow'}}>
<Button title="Tap me for first screen" onPress={() => navigation.goBack()} />
</View>
);
}

const Stack = createNativeStackNavigator();

const ButtonWithBiggerChild = () => (
<TouchableOpacity style={{width: 30, height: 30, backgroundColor: 'red'}} onPress={() => console.log("hello")}>
<View style={{width: 30, height: 30, backgroundColor: 'yellow', marginLeft: -15}}/>
</TouchableOpacity>
);

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{stackPresentation: 'modal'}}>
<Stack.Screen name="First" component={First}
options={{headerShown: true,
// headerLeft: () => <TouchableOpacity onPress={() => console.log("hello")} style={{width: 30, height: 30, backgroundColor: 'red', marginLeft: -15}}/>,
headerLeft: () => <ButtonWithBiggerChild />,
headerRight: () => <TouchableOpacity onPress={() => console.log("there")} style={{width: 30, height: 30, backgroundColor: 'red', marginRight: -15}}/>,
}}
/>
<Stack.Screen
name="Second"
component={Second}
options={{
headerLeft: () => <TouchableOpacity onPress={() => console.log("hello")} style={{width: 50, height: 50, backgroundColor: 'red', marginLeft: -15}}/>
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
17 changes: 17 additions & 0 deletions ios/RNSScreenStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,23 @@ - (void)updateContainer
[self setModalViewControllers:modalControllers];
}

// By default, the header buttons that are not inside the native hit area
// cannot be clicked, so we check it by ourselves
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(_controller.navigationBar.frame, point)) {
// headerConfig should be the first subview of the topmost screen
UIView *headerConfig = [[_reactSubviews.lastObject reactSubviews] firstObject];
if ([headerConfig isKindOfClass:[RNSScreenStackHeaderConfig class]]) {
UIView *headerHitTestResult = [headerConfig hitTest:point withEvent:event];
if (headerHitTestResult != nil) {
return headerHitTestResult;
}
}
}
return [super hitTest:point withEvent:event];
}

- (void)layoutSubviews
{
[super layoutSubviews];
Expand Down
21 changes: 21 additions & 0 deletions ios/RNSScreenStackHeaderConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,27 @@ - (void)removeFromSuperview
_screenView = nil;
}

// this method is never invoked by the system since this view
// is not added to native view hierarchy so we can apply our logic
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
for (RNSScreenStackHeaderSubview *subview in _reactSubviews) {
if (subview.type == RNSScreenStackHeaderSubviewTypeLeft || subview.type == RNSScreenStackHeaderSubviewTypeRight) {
// we wrap the headerLeft/Right component in a UIBarButtonItem
// so we need to use the only subview of it to retrieve the correct view
UIView *headerComponent = subview.subviews.firstObject;
// we convert the point to RNSScreenStackView since it always contains the header inside it
CGPoint convertedPoint = [_screenView.reactSuperview convertPoint:point toView:headerComponent];

UIView *hitTestResult = [headerComponent hitTest:convertedPoint withEvent:event];
if (hitTestResult != nil) {
return hitTestResult;
}
}
}
return nil;
}

- (void)updateViewControllerIfNeeded
{
UIViewController *vc = _screenView.controller;
Expand Down