Question

This is so bizarre that I created a new project to test if I was going mad.

You can see the project here https://github.com/ojfoggin/TapTest

I've created a project with a UITabBarController As the initial view.

The first controller tab has two UIimageViews. Each image view has a UItapGestureRecognizer on it with an action that just logs "Tap 1" or "Tap 2".

If the TabBarController isn't used then everything works fine. However if the TabBarController is used then only the first tap recognizer works, the second doesn't.

However, if you switch t a different tab and then back again then both recognisers work?!?!?

Also, I have tried adding the Tao gesture recognisers in code and exactly the same thing happens.

Can anyone explain why this is happening and how to fix it?

Was it helpful?

Solution 2

I think this comes from your app changing orientation. If you launch the app and tap on the left side (about the first third of the image) of the second UIImageView, it logs "Tap 2" correctly. I think what happens is that your app launches in portrait, switches to landscape, and messes your gesture recognizer's frame of action. When you leave and come back to the tab, the app is already in landscape, so the frame is updated correctly.

Solution : not a single clue. I only work on portrait apps, so I don't really know what happens with this orientation. That being said, the origin of the problem might not be exactly what I said. But I'd say it's something to look into.


Edit :

I logged the tap gesture x position in the main view :

NSLog(@"%f", [((UITapGestureRecognizer*)sender) locationInView:self.view].x);

The maximum x position where the gesture is recognized seems to be… 320, which is the width of a portrait app. This seems to confirm my idea of the orientation doing something to your views..


Edit 2 : Solution !

I found this thread : Landscape tab bar.

The issue comes with a UITabBarController in landscape mode. Just add the following in your viewDidLoad :

self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

I tested it and it works fine now. Remember to upvote Josh Adams' answer as it solves your problem ;]

OTHER TIPS

TL;DR

Open your storyboard file as source code (xml) and replace

<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>

with

<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES/>

For the view controller with the images.

Explanation

The problem is pretty easy to find with common debugging tools:

(lldb) po [[[[UIApplication sharedApplication] delegate] window] recursiveDescription]

shows

<UIWindow: 0x8c6a140; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x8c6a820>; layer = <UIWindowLayer: 0x8c66db0>>
   | <UILayoutContainerView: 0x8c6a320; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x8c62350>>
   |    | <UITransitionView: 0x8c6a880; frame = (0 0; 480 320); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x8c50240>>
   |    |    | <UIViewControllerWrapperView: 0x8c6cd70; frame = (0 0; 320 480); autoresize = RM+BM; layer = <CALayer: 0x8c6c840>>
   |    |    |    | <UIView: 0x8c51070; frame = (0 0; 480 271); clipsToBounds = YES; autoresize = RM+BM; autoresizesSubviews = NO; layer = <CALayer: 0x8c51d80>>
   |    |    |    |    | <UIImageView: 0x8c6bdc0; frame = (20 0; 219 160); autoresize = W+H; gestureRecognizers = <NSArray: 0x8c65180>; layer = <CALayer: 0x8c4c930>>
   |    |    |    |    | <UIImageView: 0x8c6a780; frame = (247 0; 219 160); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x8c62a70>; layer = <CALayer: 0x8c6a9a0>>
   |    |    |    |    | <_UILayoutGuide: 0x8c6c340; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x8c51110>>
   |    |    |    |    | <_UILayoutGuide: 0x8c6c760; frame = (0 271; 0 0); hidden = YES; layer = <CALayer: 0x8c6c7d0>>
   |    | <UITabBar: 0x8c64180; frame = (0 271; 480 49); autoresize = W+TM; layer = <CALayer: 0x8c642a0>>
   |    |    | <_UITabBarBackgroundView: 0x8a48e50; frame = (0 0; 480 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x8a48f40>>
   |    |    | <UITabBarButton: 0x8c64980; frame = (2 1; 236 48); opaque = NO; layer = <CALayer: 0x8c684c0>>
   |    |    |    | <UITabBarButtonLabel: 0x8c64dd0; frame = (108 35; 21 12); text = 'Item'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8c64ef0>>
   |    |    | <UITabBarButton: 0x8c69d90; frame = (242 1; 236 48); opaque = NO; layer = <CALayer: 0x8c6a250>>
   |    |    |    | <UITabBarButtonLabel: 0x8c69e70; frame = (108 35; 21 12); text = 'Item'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8c68c20>>
   |    |    | <UIImageView: 0x8a49240; frame = (0 -0.5; 480 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x8a492d0>>

where the important part is:

<UILayoutContainerView: 0x8c6a320; frame = (0 0; 320 480); autoresize = W+H;
   |    | <UITransitionView: 0x8c6a880; frame = (0 0; 480 320);autoresize = W+H
   |    |    | <UIViewControllerWrapperView: 0x8c6cd70; frame = (0 0; 320 480); autoresize = RM+BM;
   |    |    |    | <UIView: 0x8c51070; frame = (0 0; 480 271); autoresize = RM+BM

Note that the UIViewControllerWrapperView has a bad size because its autoresizing mask is not W+H but RM+BM. The root cause however is the autoresizing mask of the UIView because UIViewControllerWrapperView is generated dynamically and the mask is only copied.

If you inspect the source code of the storyboard, you will see this line:

<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>

For the view in the first view controller. Replacing it with

<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>

will fix the problem.

@Desdenova: rdurand is absolutely right. I did put some log statements in the view did load and view will appear and here is what it looks like.

2014-02-14 09:04:19.167 TapTest[3395:60b] The frame is {{0, 0}, {320, 568}}
2014-02-14 09:04:19.174 TapTest[3395:60b] The frame in viewwillappear is {{0, 0}, {320, 519}}
2014-02-14 09:04:27.814 TapTest[3395:60b] The frame in viewwillappear is {{0, 0}, {568, 271}}

The very first time in viewDidload and viewwillappear, the frame is 320,568, but when you go to the second view and come back, the frame is set properly 568,271. So the solution would be setting the frame right while the view controllers are added to the tabbarcontroller

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top