Disable passing of touches and gestures through MKMapView ViewController overlay - objective-c

I have an MKMapView with a container view which holds a view controller that I'm using as an interactive legend. I can't seem to figure out how to have the view controller (a UITableViewController in actuality) behave normally to touches but not pass them to the map view. Right now it acts like it should except if you double tap in the legend, the map view zooms in. How can I have the table view controller intercept that and any other gestures and not pass them through to the map view?

Here's what I'm doing to stop the map view moving around in a table cell:
mapCell.mapView.zoomEnabled = NO;
mapCell.mapView.scrollEnabled = NO;
Where mapCell is the cell in question and mapView is the MKMapView object showing the map.

Related

Transition from UITableView

Could recommend me any third part library to animate custom transition to new view controller directly from UITableView, where cells slides out (up and down) and smoothly transmit with opacity to new controller.
I suppose you code put in some gesture recognizers and set them as IBActions to segue to a different view controller.
In general you could just set an animation when a button as a clicked, to play the animation and then open a new view controller.

iOS7 - Setting selectedIndex of UITabBarController breaks touch events along right-hand edge of screen?

I've hit a weird problem with UITabBarController on iOS7 and can't seem to find a workaround, so any help would be welcome!
Scenario:
Navigation-based app using landscape orientation on iPad.
App consists of a main view, and a second view which is a UITabBarController.
TabBarController has two tabs.
First view has two buttons - each button performs a segue to the tab bar controller and sets a different tab as selected. (i.e. button1 selects the first tab, and button2 selects the second tab).
Setting the tab is done in prepareForSegue by calling setSelectedIndex on the tab bar controller.
Outcome:
On iOS 7 I am finding that the view shown in the tab bar controller fails to register any touch events along the right-hand edge of the view! So in the storyboard shown above, the UISwitch on the right side of the screen cannot be tapped.
I've even attached a tap gesture recognizer to the views and used it to log the area of the screen that can be touched - it seems to register touch events up to about x=770 points across. The remaining 1/4 of the screen is 'untouchable'!
After the segue, if you manually switch to the other tab and switch back again, the touch events are 'fixed' and the full view responds to touches again.
This doesn't seem to be a problem on iOS 5 / 6.
Any help much appreciated as to:
What is causing this to happen in the first place (iOS7 bug / change?)
How else can I work around this? I've tried calling setSelectedViewController as well as using setSelectedIndex and this seems to be the same.
Thanks in advance.
I ended up raising this with Developer Tech Support, and it looks like a bug. This is the response I got back from Apple:
The container view that the tab bar controller sets up to contain your view controller is not being resized to account for the interface being in landscape orientation. It's dimensions at the time your view controller is displayed are 768 (width) x 1024 (height).
The view hierarchy looks like this when the selected tab's view is displayed:
UIWindow
/* Navigation Controller */
UILayoutContainerView
UINavigationTransitionView
UIViewControllerWrapperView
/* Tab bar controller */
UILayoutContainerView
UITransitionView
UIViewControllerWrapperView <-- Incorrectly sized.
/* MyViewController */
MyViewController.view
The incorrect size of UIViewControllerWrapperView does not cause a display problem because subviews are still displayed even if they are outside their superview's bounds. However, event routing is much more strict. Events on the right quarter of the screen are never routed to your view controller's view because the hit test fails at the wrongly-sized UIViewControllerWrapperView where the event falls outside UIViewControllerWrapperView's bounds.
As a workaround, I subclassed UITabBarController, and added the following in viewWillAppear:
#implementation FixedIOS7TabBarController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Fix the frame of the UIViewControllerWrapperView
self.selectedViewController.view.superview.frame = self.view.bounds;
}
#end
Hope that helps someone else....
As explained in this answer,
The container view that the tab bar controller sets up to contain your
view controller is not being resized to account for the interface
being in landscape orientation. Its dimensions at the time your view
controller is displayed are 768 (width) x 1024 (height).
I was encountering this problem when the TabBarController was originally displayed in portrait mode. When the device was rotated into landscape mode, the view was unresponsive on the right hand side.
The solution proposed in that answer did not work for me, because viewWillAppear: is invoked only once. However, viewDidLayoutSubvews is invoked whenever the view changes, including rotations, so my solution was to subclass UITabBarController and perform the workaround in viewDidLayoutSubvews:
#implementation FixedIOS7TabBarController
- (void)viewDidLayoutSubviews
{
// fix for iOS7 bug in UITabBarController
self.selectedViewController.view.superview.frame = self.view.bounds;
}
#end
End up finding a workaround here:
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Right answer don't worked for me, cause user can change orientation; And it still not touchable in some area when change orientation.
So I create my own solution, I don't sure that is normal solution.
#implementation FixedIOS7TabBarController
- (UIView*)findInSubview:(UIView*)view className:(NSString*)className
{
for(UIView* v in view.subviews){
if([NSStringFromClass(v.class) isEqualToString:className])
return v;
UIView* finded = [self findInSubview:v className:className];
if(finded)
return finded;
}
return nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIView* wraperView = [self findInSubview:self.view className:#"UIViewControllerWrapperView"];
wraperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
#end
Works perfectly for me!
In the list of view controllers on the left hand side navigate to the views/view controllers affected, drag the view to underneath the first responder so that it is disassociated to the view controller's view.
Then go to the layout tab on the right hand side, select all 4 anchors and both sets of resizing arrows (horizontal + vertical).
Then drag the view back to where it was originally (just below the view controller).

How to store orginal frame of UIView subclass loaded from storyboard automatically

I have a subclass of UIView which is has a property called originalFrame.
I want this class to store the original it's original frame value after it loaded from the storyboard it is apart of.
I have overridden the awakeFromNib method:
-(void)awakeFromNib
{
self.originalFrame = self.frame;
}
This works if the view of the view controller it is apart of is not resized right after to fit the screen size.
However, the view controllers in my storyboard are all for the iPhone 4-inch screen, so when the app runs on an iPhone 3.5 inch screen, awakeFromNib is called before the view controller's view is resized to fit the 3.5 inch screen. If my subview is not anchored to the top, then the originalFrame property won't reflect its frame after the resize.
I was able to override layoutSubviews to get the frame property after the view controller's view was resized, but this method is called other times too and I have no way of knowing if it is for the initial resize to fit screen, or something else.
Is there any way to do this without having to set this property manually on a case by case basis in the viewDidLoad method of the view controller?
You can check if the value is already set if you set it in awakeFormNib to CGRectZero and check in layoutSubviews if it is CGRectZero. Only set the frame in layoutSubviews if it is CGRectSubviews.

Different "highlighted" color for accessory view based on what was tapped?

My designers have come up with a design that's a bit tricky. In a tableView, they want me to
1) have a custom accessory view - (UIButton subview) - DONE
2) give a custom action (no detailView pushed to a navigation stack but something else) to a tapped cell accessory - DONE
Now comes the tricky part.
1) If I tap the cell, the accessory view should show a "highlightedBackground".
2) If I tap the accessory view, only the accessory view should highlight, but with "alternativeHighlightedBackground".
So to recap, for the accessoryView, we have normal background and two different highlighted backgrounds, depending on whether the whole cell was tapped, or only the accessory view was tapped.
At the moment, I am adding a UIButton as a subview to the accessory view in cellForRowAtIndexPath, that serves as a custom accessory. Obviously, the accessory view passes the touch event to the button, and the button highlights with the same background, regardless of what was tapped.
The cell is not custom at the moment, its a normal UITableViewCell instance.
The SDK is iOS5, unfortunately no iOS6 can be used.
Any advice?
I would abandon the accessory view route, and create a subclass of UITableViewCell. Simply create you button in the init function, add it as a subview to the contentView of the cell, set the buttons's touch-up action to be what ever you want, then override layoutSubviews with something that looks like this:
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect bounds = self.contentView.bounds;
CGFloat buttonOriginX = self.contentView.bounds.size.width - BUTTON_WIDTH - PAD;
CGFloat buttonOriginY = floorf((bounds.size.height - BUTTON_HEIGHT)/2.0)+1;
self.mybutton.frame = CGRectMake(buttonOriginX, buttonOriginY, BUTTON_WIDTH, BUTTON_HEIGHT );
}
The button will intercept touches before the cell will this way. You can then be in complete control of what the buttons displays when it is touched (set setting it's highlight state image).

Flip Animation in a navigation controller's view

i am testing all day on this but i can not get it to work.
I have my main App Delegate class with my MainWindow.xib.
In this main class i create my navigation controller and MainWindow points to my MainViewController.xib. In this MainViewController i have a simple tableview, where i push some views on the navigation stack.
Till here it's working great.
But i want the user to switch between two styles of presenting him data.
One is the tableview, and the other option is something like a map. Doesn't matter. Just 2 different Views. So i thought of using a button on my nav bar to flip between these two views.
Don't get this subview flip to work.
I tried it with that source but didn't get it to work.
Some hints would be great!
Suppose you have all the navBar, buttons ready. You can use modal view for the solution:
-(void)changeView{
//create some view
[youNewView setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:youNewView animated:YES];
}
You can use the above method to flip to a new view.
-(void) dismissView{
[self dismissModalViewControllerAnimated:YES];
}
and use the second method in the new view to flip back.
I like this method a lot because you don't need to add any controller manually at all.