MKMapView click on pin causes weird frame changes - ios

I created not custom, simple pin annotations on MKMapView and when I click on it, I'm getting following for my MapView:
It happens only on iOS8.
I figured out that without constraints for mapView - it works fine.
Constraints are simple - just to be fullscreen when rotating device.
here are they:
[self.mapView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0]];
MapView is added to ViewController.view and I'm not getting any warnings about conflicting constraints so on.
Why it happens?
And what is most unfair why clicking on MapView annotation causes it...

I didn't go to details but for some reasons mapView after clicking on annotation had a center in left/top corner of parent view,
so setting center anchor did the trick:
[self.mapView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = true;
[self.mapView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = true;
I guess this is because I specified height/width constraints but nothing about positioning, so defining top/left constraints,
also could help

Related

How to add subview with half-transparent background which won't break and won't be affected by AutoLayout?

I want to show user that application is loading data using some progress bar and label on top of view which will be shown after the data is loaded. This view is not initial, so I cannot use LaunchScreen for these purposes. What's the best way to do so?
The view which will be shown after uses AutoLayout, and it'd better be that view on top uses AutoLayout as well, but those AutoLayouts shouldn't interact with each other in any way.
First create a custom UIView class, and customize the view according to your requirement. i.e. transparent background, add image/label etc. using autolayout/with the help of code.
Now add this custom view (yourSubView) into its containerview and add some constraint so that it place in right location.
The following code will add a subview after keep space 80px in all side (left, right, top, bottom), you can add constraint according to your requirement.
[yourContainerView addSubview:yourSubView];
yourSubView.translatesAutoresizingMaskIntoConstraints =
NO;
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeRight multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeTop multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:80.0]];
What about using something like https://github.com/sgryschuk/SGNavigationProgress?

iOS - replicating a constraint programmatically

I created this constraint in Interface Builder. Without it, the below textview expands upwards as its content grows, with it, the textview expands downwards as its content grows.
How do I create that constraint in programmatically?
Here is what I tried:
[self addConstraint:[NSLayoutConstraint
constraintWithItem:_textView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_internalScrollView //this is the parent view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0]];
but it has no material affect on anything.
The UITextView object I am using is from this library https://github.com/MatejBalantic/MBAutoGrowingTextView but that is a red herring to this question.
Here is what you need to do.
[_internalScrollView addConstraint:[NSLayoutConstraint
constraintWithItem:_textView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_internalScrollView //this is the parent view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:300.0]]; // constant should be 300 as shown by you in screen shot
btw, the above screen shot shows you are making constraint with top layout guide and not with parent view of textView if that is the case then layout attributes should be changed in the above code according to your needs

iOS: Autolayout differences with appliying constraints to subview on iOS 7 and iOS 8

I have a view controller set up in a storyboard. The view controller's view contains a subview(UITableView) with pinned edges to the 4 sides of its parent, essentially making the view fill its parent.
I am adding the view controller's main view as a subview of another view controller's view like this:
UIView *overlayView = firstViewController.view;
[overlayView setTranslatesAutoresizingMaskIntoConstraints:NO];
UIView *sourceView = secondViewController.view;
[sourceView addSubview:overlayView];
NSLayoutConstraint *constraint;
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:sourceView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:overlayView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:100];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
[sourceView layoutIfNeeded];
I want to have a gap from the right edge of the view to its parent equal to 100 pixels.
Now weirdly enough this works as expected on iOS 8, but fails to do so on iOS 7 and the view is displayed full-screen ignoring the 100 constant set on the trailing constraint. Also, if the view controller's view that is being added has no child views - then it is working as expected. Is setTranslatesAutoresizingMaskIntoConstraints: being applied to all the subviews of a view in iOS 7 ? What might be the reason for this ?
EDIT:
The issue lies somewhere in the way subviews are being managed by the OS.
When the Container View is set as a outlet to the view property of the view controller, things don't work. If however, I set the Table View as an outlet to the view property, the it works. Something weird happens if there is a child view with pinned edges to its superview and then I am adding other constraints to the superview. I dont understand why it works fine on iOS 8 though...
EDIT 2
The problem seems to happen only with the trailing constraint. If I want to modify the constants of any of the other constraints there are no issues ?!
Can you try interchanging sourceView with overlayView in your constraint?
`constraint = [NSLayoutConstraint constraintWithItem:sourceView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:overlayView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:100];`
This essentially means that sourceView.trailing - 100 = overlayView.trailing; which is not what you would want.
Edit 1:
Is setTranslatesAutoresizingMaskIntoConstraints: being applied to all the subviews of a view in iOS 7?
NO. translatesAutoresizingMaskIntoConstraints is set only for the views you explicitly call setTranslatesAutoresizingMaskIntoConstraints for.

Center UIView on screen using Auto Layout programmatically when the view is located at the top of the view hierarchy

I have implemented a popup UIView which I add to the topmost window via [[[[UIApplication sharedApplication] windows] lastObject] addSubview:popupView], so it will appear on top of everything even the keyboard. I need to ensure this popup view that I programmatically created will always remain centered on screen. I was attempting to add auto layout constraints, but it doesn't like the fact I'm trying to align with the topmost window. Could you let me know how I could accomplish this? Thank you.
This is what I have implemented, which will generate a (nicely detailed) error that states 'The view hierarchy is not prepared for the constraint ... the constraint's items must be descendants of that view':
[popupView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *cn = nil;
cn = [NSLayoutConstraint constraintWithItem:popupView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:[[[UIApplication sharedApplication] windows] lastObject]
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[popupView addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:popupView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:[[[UIApplication sharedApplication] windows] lastObject]
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
[popupView addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:popupView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:blockSize.height];
[popupView addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:popupView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:blockSize.width];
[popupView addConstraint: cn];
Don't go sticking your view into a window that wasn't set up specifically to hold your views. You don't know what the real owner of that window might do, now or in a future version of iOS.
Create your own window and set its windowLevel high enough to be above the keyboard. Give the new window its own root view controller (so it will handle different orientations properly) and center your popup view inside that root view controller's view.
You will find lots of useful information in the answers to this question.
It's fine to add the height and width constraints to popupView, but since popupView is a subview of the window, the centering constraints should be added to the window, not the popupView (and you need to add the popupView as a subview first, before you add the constraints).

Adding constraints without auto-layout

I am building an app with a modal view containing a UICollectionView and below it a view containing two buttons (validate/cancel).
The number of rows in my UICollectionView can change depending on the data and don't know it beforehand so I want to add a constraint to always keep my buttons 30px below the collectionView.
I am not using auto-layout for this as I have some animations which work better without it so I don't know how to programmatically add such constraints.
Does anyone have any idea how to do it?
Many thanks for your help
I am not sure about the collection view. However, the below works with a standard view and since UICollectionView is a type of UIView, then the code might work with collection view also
NSLayoutConstraint *bottomConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:0.45 constant:0];
NSLayoutConstraint *widthConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:95];
NSLayoutConstraint *heightConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:95];
NSLayoutConstraint *leftConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:20];
[self.view addConstraints:#[bottomConstraint,widthConstraint,heightConstraint,leftConstraint]];
The above basically lays out the buttonA relative to the view. However, to use this, the auto layout should be off (as in your case).
The bottom Constraint says that this constraint is related to button A and will act on its attribute NSLayoutAttributeBottom(bottom side) and the bottom side will be present on exactly 0.45*(Bottom of view).
The width constraint specifies that it is related to button A and will act on its width. The width is not dependent on any other object (toItem is nil) and it will have a constant value of 95.

Resources