MKMapView defaults to 1000x1000 in Xcode8 - objective-c

I'm wondering if anyone else has the issue that MKMapView (Or maybe it relates to many other Views?) does a strange thing where it defaults to 1000x1000 in size the first time I load a screen. When I segue to another screen, and segue back to the map screen, then it actually followed up all my constraints.
This didn't happen with Xcode7 and I wonder if someone knows there's a known bug in Xcode8 or something?
MapKitView get loaded programmatically and is added as a subview within my View that has the constraints.
MKMapView *mapkitView = [[MKMapView alloc] initWithFrame:self.aConstrainedView.frame];
[self.mapkitView setDelegate:self];
[self.mapkitView setShowsUserLocation:YES];
[self.mapkitView setRotateEnabled:NO];
[self.aConstrainedView addSubview:self.mapkitView];
Could this be related to Autoresizing issue in Xcode 8 ?

Your initialiser should use the bounds of its superview, not the frame:
MKMapView *mapkitView = [[MKMapView alloc] initWithFrame:self.aConstrainedView.bounds];
Set a breakpoint on this line and in the debugger use:
(lldb) po self.aConstrainedView.bounds
to ensure the width and height are correct. If you're adding the map view in viewDidLoad, then that's too early. You should override:
- (void)viewDidLayoutSubviews {
dispatch_once(
// Add map view here
);
}
and add your code in there, as that gets called after your subviews have all been laid out according to your constraints.

Related

Adding NSView to window not on top?

I am adding a subview programmatically and adding it to the main windows context view to cover up the entire context view like so:
loadingView = [[LoadingView alloc] initWithFrame:[mainWindow.contentView frame]];
NSLog(#"%#", [mainWindow.contentView subviews]);
[mainWindow.contentView addSubview:loadingView];
NSLog(#"%#", [mainWindow.contentView subviews]);
[mainWindow makeFirstResponder:loadingView];
The NSLog's confirm that loadingView is being added last in the contentView subviews. I have also tried:
loadingView = [[LoadingView alloc] initWithFrame:[mainWindow.contentView frame]];
[mainWindow.contentView addSubview:loadingView positioned:NSWindowAbove relativeTo:nil];
[mainWindow makeFirstResponder:loadingView];
That didn't work either. For some reason the two tableviews (created in IB) at the bottom of the window are on top of the new view I've added. Here's a snapshot of the window, note that the red part is what should be on top with the progress bar and a few labels:
It's also worth noting that the view has it's alpha set to 0.9 which is why you can somewhat see behind it.
GW
If you place one view above another, the objects in the previous view will be visible in above view. What you need do is remove previous views from window and then add a new subview.
Try using:
//Create IBOutlet of your tableview in your .h file
IBOutlet NSTableView* yourTableView;
// Add this line where you are adding your subview to remove the tableview from superview.
[yourTableView removeFromSuperview];
// Then add your loading view as the subview
loadingView = [[LoadingView alloc] initWithFrame:[mainWindow.contentView frame]];
[mainWindow.contentView addSubview:loadingView];
Then whenever your want your tableView back use:
[window contentView]addSubview: yourTableView];
As long as you use nil here, you will not get predictable results.
[mainWindow.contentView addSubview:loadingView positioned:NSWindowAbove relativeTo:nil];
If you have not already done so, put all the other views inside a containing view.
Make the containing view the only view that is a direct child of the window content view.
Now add your subview with the above method and replace nil with a reference to the containing view.
In OS X, overlapping siblings have certain nuances when it comes to drawing. In your case, the loadingView and the two table views are siblings because they are all added as subviews of the window's content view and they overlap hence the nuances are coming into play.
From Apple's Documentation
For performance reasons, Cocoa does not enforce clipping among sibling
views or guarantee correct invalidation and drawing behavior when
sibling views overlap. If you want a view to be drawn in front of
another view, you should make the front view a subview (or descendant)
of the rear view.
I don't have the definitive solution for this but reading these should help improve your understanding for the long term.
http://www.cocoabuilder.com/archive/cocoa/327817-overlapping-sibling-views.html
Is there a proper way to handle overlapping NSView siblings?

UIButton inside UIView doesn't respond to touch events

I've put a UIButton inside a custom UIView and the button is not receiving any touch events (it doesn't get into the highlighted state, so my problem is not about being unable to wire up a touch inside up handler). I've tried both putting it into the XIB in Interface Builder, and also tried programatically adding the UIButton into the UIView seperately, both ended with no luck. All my views are inside a UIScrollView, so I first though UIScrollView may be blocking them, so I've also added a button programatically exactly the same way I add my custom view into UIScrollView, and the button worked, elimination the possibility of UIScrollView could be the cause. My View's hiearchy is like this:
The button is over the image view, and the front layer isn't occupying my button completely, so there's no reason for me not be physically interacting with the button. At my custom view's code side, I'm creating my view as such:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *sub = [[[NSBundle mainBundle] loadNibNamed:#"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
/*layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 20.0;
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.8;
*/
}
return self;
}
I've tried all combinations of setUserInteractionsEnabled, and had no luck. (Yes, also set them to checked in Interface Builder too). I've also read in another question with a similar problem that I should try overriding 'canBecomeFirstResponder' to return 'YES' and I've also done that too. But the problem persists, I can't click the button. I've not given any special properties, settings to the button, it's just a regular one. My other objects in the view (labels below, image view behind the button etc.) are working properly without problems. What could be possibly wrong here?
Thanks,
Can.
UPDATE: Here is a quick reproduction of the problem: https://dl.dropbox.com/u/79632924/Test.zip
Try to run and click the button.
Looking at the test project, I believe your problem in the way you create TestView, you do not specify the frame for it, so basically the parent view is 0 size, and the subviews you see from XIB extending out of the parent view and thus do not get anything in responder chain.
You should either specify the frame when creating TestView, or adjust the frame after loading XIB file.
I have had this problem as well. The cause for me was that the UIButton superview frame was of height 0, so I believe that even though a touch was happening, it was not being passed down to the button.
After making sure that the button's superview took a larger rectangle as a frame the button actions worked.
The root cause for this problem on my side was a faulty auto layout implementation (I forgot to set the height constraint for the button's superview).
I've found the solution. I was initializing my custom view as:
MyView *view = [[MyView alloc] init];
I've initialized it instead with a frame of my view's size, and it started responding to events:
CGRect rect = CGRectMake(0,0,width,height);
MyView *view = [[MyView alloc] initWithFrame:rect];
Storyboard Solution
Just for anyone wanting a solution to this when using storyboards and constraints.
Add a constraint between the superview (containing the button) and the UIButton with an equal heights constraint.
In my case, I had selected embed UIButton in a UIView with no inset on the storyboard. Adding the additional height constraint between the UIButton and the superview allowed the UIButton to respond to touches.
You can confirm the issue by starting the View Debugger and visually confirm that the superview of the UIButton is not selectable.
(Xcode 11, *- Should also work in earlier versions)

setting an accessibilityLabel on a UIImageView contained in UITableView header

I have a UITableView that I build in loadView. One of the things I do in loadView is create a UIView to act as the table header and stuff a UIImageView into it. The image view contains an image that is a stylized title, so I want to add an accessibility label for VoiceOver users. However, I can't get VoiceOver to "focus" on the image in order to read the label, and the Accessibility Inspector doesn't respond to clicking on the image in the simulator. My (abbreviated) code follows:
... in -loadView ...
// Make header view
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(...)];
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:[self titleImage]];
titleImageView.accessibilityLabel = [self accessibilityLabelForTitleImage];
[headerView addSubview:titleImageView];
// Make table view
self.tableView = [[UITableView alloc] initWithFrame:CGRect(...) style:UITableViewStylePlain];
self.tableView.tableHeaderView = headerView;
... code continues ...
I've stepped through in gdb and accessibilityLabelForTitleImage returns a string. po [titleImageView accessibilityLabel] prints out the correct string, but I'm still unable to focus on the image view. Note that the views themselves appear and respond as appropriate.
Am I missing something? Is there a way to force VoiceOver to acknowledge an image view?
In Voice-Over , in order to make an element accessible :-
you have to set setIsAccessibilityElement property as true which i don't find in your code.
The other important point is that to make child elements (subviews) to be accessible , you have to seperately make them accessible while the parent should not be accessible(you have to specify this also).
Implement the UIAccessibilityContainer Protocol in your custom - cell.
It will be a big story if i go on .Please refer this Accessibility voice over by apple.
Hope this helps.
I used KIF for testing my IOS app. In my tableview, I assigned value to tableview.accesssibilityIdentifier instead of tableview.accessibilityLabel. It worked for me. Wanna give it a try?
Voice-Over sometimes can get nasty and just by setting isAccessibilityElement might not work.
In this case try setting accessibilityElements on the parent view and include the child views in the array, like this:
parentView.accessibilityElements = [childView1, childView1, childView1]
Doing it also ensures that the accessibility items are being read in the order you want.

Overriding layoutSubViews: causes "CGAffineTransformInvert: singular matrix" randomly

I'm overriding layoutSubViews: in a UIScrollView and from time to time I get "CGAffineTransformInvert: singular matrix" for every subview I reposition. The layout looks totally okay however.
The app does not crash either.
Does anybody know what causes this?
I once had this error cause by mistake was setting a font with size 0 when using
[UIFont fontWithName:size:]
for a UILabel.
In case anyone else is struggling with this (and in case it's not because of setting the label font size to 0), "CGAffineTransformInvert: singular matrix" seems to come up when layoutSubViews: runs on a view (such as UIScrollView or UILabel) that has a frame of size (0,0).
Took me forever to figure out because if your container view (e.g. the scroll view) is not set up to clip subviews, the layout will still look fine.
I was seeing this problem too when I added a UIWebView to my self.view.
The offending code was:
UIWebView *wv = [[UIWebView alloc]init];
and the solution is:
UIWebView *wv = [[UIWebView alloc]initwithFrame:[[UIScreen mainScreen]bounds]];
or any framesize except 0.0.
In my application I got this error as I forget to call the -layoutSubViews of the superClass in the overridden -layoutSubViews method,
so make a call [super layoutSubViews] at any point in your overridden method

Why is this UIImageView autocentering itself?

I have a UIImageView in a UIScrollView in another UIScrollView (based on Apple's
PhotoScroller sample code). When the UIScrollView calls back to its controller to dismiss itself, it calls this method:
- (void)dismiss {
[scrollView removeFromSuperview];
ImageScrollView *isv = [self currentImageScrollView];
UIImage *image = isv.imageView;
image.frame = [self.view convertRect:image.frame fromView:isv];
[self.view insertSubview:image belowSubview:captionView];
[(NSObject *)delegate performSelector:#selector(scrollViewDidClose:)
withObject:self
afterDelay:2.0];
}
Now here's the weird part: the image view jumps to a different position right after this method executes, but before the scollViewDidClose method gets called on the delegate. If the image is larger than its new super view, it jumps so that its left edge is aligned with the left edge of its super view. If it's smaller than its new super view, it jumps to the very center of the view. There is no animation to this change.
So my question is, how do I prevent it from doing that? I've tweaked both the super view (self.view) class and the image view class to see what methods might be called. Neither the frame nor the center is set on the image view after this method is called, and while the layoutSubviews method is called on the super view, that is not what jumps the image to the center or left side of the superview. I've also tried turning off autoResizesSubviews in the super view, and setting the autoresizingMask of the image view to UIViewAutoresizingNone, with no change in behavior.
So where is this happening, and why? And more importantly, how do I make it stop?
I've been beating my head on this for days. Any pointers or guidance would be greatly appreciated.
ImageScrollView is the one centering your UIImageView. Set a breakpoint in ImageScrollView layoutSubviews and you'll see how your UIImageView is being centered.
You're taking ImageScrollView's internal imageView and placing it into another view. That's not going to work because ImageScrollView still retains ownership of that UIImageView instance and is still managing its layout.
You'll either need to copy the image into another UIImageView instance, or you'll need to change ImageScrollView to allow it to relinquish ownership of its imageView.
You're not setting up the frame of the 'image' view when you insert it as a subview. You probably want to do that explicitly if you want the view to appear at a particular position in the scroll view.