Skip to content

Commit

Permalink
Fix bottomTabs long press event (#6327)
Browse files Browse the repository at this point in the history
Until now, `bottomTabs` longPress event gesture was implemented wrong and caused this [bug](#6305).
It also reported wrong index in the first place, starting from 1 instead of 0.
This PR fixes both issues.

Closes #6305
  • Loading branch information
yogevbd authored Jun 22, 2020
1 parent 32af157 commit 814de45
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 14 deletions.
2 changes: 2 additions & 0 deletions lib/ios/RNNBottomTabsController.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

- (void)setTabBarVisible:(BOOL)visible;

- (void)handleTabBarLongPress:(CGPoint)locationInTabBar;

@property (nonatomic, strong) NSArray* pendingChildViewControllers;

@end
30 changes: 19 additions & 11 deletions lib/ios/RNNBottomTabsController.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ @interface RNNBottomTabsController ()
@property (nonatomic, strong) BottomTabPresenter* bottomTabPresenter;
@property (nonatomic, strong) RNNDotIndicatorPresenter* dotIndicatorPresenter;
@property (nonatomic) BOOL viewWillAppearOnce;
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressRecognizer;

@end

@implementation RNNBottomTabsController {
Expand Down Expand Up @@ -33,6 +35,10 @@ - (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo
if (@available(iOS 13.0, *)) {
self.tabBar.standardAppearance = [UITabBarAppearance new];
}

self.longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
[self.tabBar addGestureRecognizer:self.longPressRecognizer];

return self;
}

Expand Down Expand Up @@ -63,14 +69,6 @@ - (void)render {

- (void)viewDidLayoutSubviews {
[self.presenter viewDidLayoutSubviews];

for (UIView *view in [[self tabBar] subviews]) {
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(handleLongPress:)];
if ([NSStringFromClass([view class]) isEqualToString:@"UITabBarButton"]) {
[view addGestureRecognizer: longPressGesture];
}
}

[_dotIndicatorPresenter bottomTabsDidLayoutSubviews:self];
}

Expand Down Expand Up @@ -131,16 +129,26 @@ - (void)setTabBarVisible:(BOOL)visible {
}
}

- (void)handleTabBarLongPress:(CGPoint)locationInTabBar {
for (UITabBarItem* item in self.tabBar.items) {
if (CGRectContainsPoint([[item valueForKey:@"view"] frame], locationInTabBar)) {
NSUInteger tabIndex = [self.tabBar.items indexOfObject:item];
[self.eventEmitter sendBottomTabLongPressed:@(tabIndex)];
break;
}
}
}

#pragma mark UITabBarControllerDelegate

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self.eventEmitter sendBottomTabSelected:@(tabBarController.selectedIndex) unselected:@(_previousTabIndex)];
}

- (void)handleLongPress:(UILongPressGestureRecognizer *) recognizer {
- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSUInteger _index = [self.tabBar.subviews indexOfObject:(UIView *)recognizer.view];
[self.eventEmitter sendBottomTabLongPressed:@(_index)];
CGPoint locationInTabBar = [recognizer locationInView:self.tabBar];
[self handleTabBarLongPress:locationInTabBar];
}
}

Expand Down
2 changes: 2 additions & 0 deletions lib/ios/UITabBar+utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

@interface UITabBar (utils)

- (UIView *)tabBarItemViewAtIndex:(NSUInteger)index;

- (void)centerTabItems;

@end
4 changes: 4 additions & 0 deletions lib/ios/UITabBar+utils.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

@implementation UITabBar (utils)

- (UIView *)tabBarItemViewAtIndex:(NSUInteger)index {
return [self.items[index] valueForKey:@"view"];
}

- (void)centerTabItems {
[self removeTabBarItemTitles];
[self swizzleUITabBarButton];
Expand Down
13 changes: 13 additions & 0 deletions playground/ios/NavigationTests/BottomTabsControllerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#import <ReactNativeNavigation/BottomTabPresenterCreator.h>
#import "RNNBottomTabsController+Helpers.h"
#import "RNNComponentViewController+Utils.h"
#import <ReactNativeNavigation/UITabBar+utils.h>

@interface BottomTabsControllerTest : XCTestCase

Expand Down Expand Up @@ -197,6 +198,18 @@ - (void)testDidSelectViewController_emitEventOnTabPress {
[(id)uut.eventEmitter verify];
}

- (void)testTabLongPress_ShouldEmitEvent {
RNNNavigationOptions *options = [[RNNNavigationOptions alloc] initEmptyOptions];
RNNComponentViewController *vc = [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:nil options:nil defaultOptions:nil];
RNNBottomTabsController *uut = [RNNBottomTabsController createWithChildren:@[[UIViewController new], vc] options:options];
[uut viewWillAppear:YES];
[uut.tabBar layoutSubviews];
[[(id)uut.eventEmitter expect] sendBottomTabLongPressed:@(1)];
UIView* secondTabItemView = [uut.tabBar tabBarItemViewAtIndex:1];
[uut handleTabBarLongPress:secondTabItemView.center];
[(id)uut.eventEmitter verify];
}

- (void)testOnViewDidLayoutSubviews_ShouldUpdateDotIndicatorForChildren {
id dotIndicator = [OCMockObject partialMockForObject:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil]];
RNNComponentViewController *vc = [[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:nil options:nil defaultOptions:nil];
Expand Down
6 changes: 3 additions & 3 deletions playground/src/app.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-check
const Navigation = require('./services/Navigation');
const { registerScreens } = require('./screens');
const { Platform } = require('react-native');
const { setDefaultOptions } = require('./commons/Options')
const {registerScreens} = require('./screens');
const {Platform} = require('react-native');
const {setDefaultOptions} = require('./commons/Options')
const testIDs = require('./testIDs');
const Screens = require('./screens/Screens');

Expand Down

0 comments on commit 814de45

Please sign in to comment.