MKMapView and viewDidLoad/viewWillAppear/viewDidAppear using Storyboards - objective-c

I have a ViewController with a MapView, the controller is initialized by a segue specified in the storyboard. The MapView is connected (via Storyboard) to a property in the controller.
.h file
#interface DetailViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *locationMapView;
I am using a method to center the MapView to a specific region:
- (void)centerMapView
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(geoPoint.latitude, geoPoint.longitude), 1000, 1000);
[self.locationMapView setRegion:region animated:NO];
NSLog(#"size height: %f",self.locationMapView.frame.size.height);
NSLog(#"size width: %f",self.locationMapView.frame.size.width);
}
Calling this method from viewDidLoad/viewWillAppear does nothing for the first time, but centers it correctly for the second time the View is loaded.
The Log output is always:
size height: 0.000000
size width: 0.000000
When called in viewDidAppear the MapView is centered and the output size is correct:
size height: 400.000000
size width: 320.000000
I guess the size values mean that the view is not yet initialized in viewDidLoad/viewWill appear, this might be unrelated to the my problem with setting the region.
I am wondering, if it is really not possible to set the region of the MapView in viewDidLoad/viewWillAppear so the user does not see a changing of the region.
Any advice?

The view size issue probably is unrelated to your problem with setting the region.
The key question: when is DetailViewController's geoPoint property set, relative to when its view gets loaded? If viewDidLoad runs before you set that property (presumably from prepareForSegue:sender: in another view controller), geoPoint will be nil (zero) when you try to center the map, so it won't center it correctly. (And it works the second time because the instance of DetailViewController already exists and has its geoPoint from the previous time.)
You might consider calling your centerMapView method from a custom setter for your geoPoint property -- that way you're guaranteed that it'll happen once the view controller has the appropriate data, which will still be before it appears so there won't be a visible map transition.

Related

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.

Inconsistent state of NSSplitView

I am playing around with NSSplitView - quite successfully for now but here is my Problem:
My SplitView looks like this:
Test project here: https://www.dropbox.com/s/amz863l11nvkdir/TestNSSplitView.zip
I've implemented - (void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize to stick the left and the right subview at the same size as before while resizing.
If I open the Window which contains the NSSplitView this message comes up in the console:
<NSSplitView: 0x107de1520>: the delegate <BRSchematicWindowController: 0x10ac11050> was sent -splitView:resizeSubviewsWithOldSize: and left the subview frames in an inconsistent state:
Split view bounds: {{0, 0}, {1068, 600}}
Subview frame: {{0, 0}, {182, 600}}
Subview frame: {{183, 0}, {640, 600}}
Subview frame: {{824, 0}, {243, 600}}
The outer edges of the subview frames are supposed to line up with the split view's bounds' edges. NSSplitView is working around the problem, perhaps at the cost of more redrawing. (This message is only logged once per NSSplitView.)
What is wrong here? I didn't get it even after reading this message...
PS: In the right splitView there is another NSSplitView this isn't the failure. I get this message even without this additional NSSplitView.
If you're targeting OS X 10.6+, then it's much easier to use NSSplitView's splitView:shouldAdjustSizeOfSubview: to control sizing.
One way to use this method would be to add the following IBOutlets to your .h file:
#property (nonatomic, weak) IBOutlet NSView *leftView;
#property (nonatomic, weak) IBOutlet NSView *centerView;
#property (nonatomic, weak) IBOutlet NSView *rightView;
Then implement splitView:shouldAdjustSizeOfSubview: in your .m file like this:
- (BOOL)splitView:(NSSplitView *)aSplitView
shouldAdjustSizeOfSubview:(NSView *)subview {
return (subview == _centerView);
// or return !(subview == _leftView || subview == _rightView);
}
By implementing that, you basically say "only adjust the size of center subview when resizing".
You can comment out the entire splitView:resizeSubviewsWithOldSize: method for the time being unless you need to customize the default behavior in some way.
Note that if you have multiple split views that have this controller object set to be their delegate, you may want to check to see which split view is being passed in the aSplitView parameter and do different things accordingly.

How can I set the size of a UIView init with storyboard?

I am currently using iOS 6.0.
I have a custom UIView that needs to have a certain size. If I programmatically init the view and add it it's fine. However, I can't find a place where I can set the size of the view in the storyboard.
Setting its size in the storyboard doesn't work because the storyboard thinks it's empty and set it's size to zero. Setting its size in viewDidLoad or viewDidAppear doesn't work because later on the size will be overwritten by _applyISEngineLayoutValue.
You can do that in your Interface Builder. Open the storyboard where you have your view and open the utilities menu:
Then you can select a button that looks like a ruler on the top of the utilities menu:
In that menu you can set the size of your view and how you want it to expand.
Also, please make sure you setted your Class' view in the class inspector:
Image token from this site.
Finally, make sure you override the initWithFrame and initWithCoder methods:
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
//Needs to be overrided when you set your size in interface builder
- (id)initWithCoder:(NSCoder *)aDecoder {
return [self initWithFrame:[self frame]];
}
I am facing the same problem, and I think the short answer is: you can't rely on the frame or bounds in the view's init method when using storyboards.
When your view is initialized by the segue, it will call the initWithCoder: method rather than other init methods, since it is deserializing your view object from the .xib file. Before storyboards, the frame and bounds would be set by the time the initWithCoder: was called, but that appears to no longer be the case with storyboards -- the iOS code sets those values later.
I've used a couple workarounds, depending on the situation:
If I know the size of the view in advance (for example a specialty view that only supports one size) I set my own frame in the initWithCoder: method.
If I don't know the size of the view, I defer initialization of size-specific things until my view's layoutSubviews method is called.
If it's more convenient, I sometimes just explicitly do the size-specific initialization in my view's ViewController. (Not pretty, but sometimes quick-and-easy. I'm not proud.)
I have the same problem as you, and when I select the view and switch to the attributes inspector , setting
"Simulated Metrics" as follows, I can resize the view in the Size inspector.
Make sure that Size is set to either "Freeform" or "None"

Embed ImageView in ScrollView with Auto Layout on iOS 6

I am trying to make very simple element with new iOS 6 SDK with auto layout.
I have an ImageView and Embed it in ScrollView. (everything build with Interface Builder). The .png file is set and imageView mode is set to "Top Left".
Implementation:
#import "ImaginariumViewController.h"
#interface ImaginariumViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#end
#implementation ImaginariumViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.contentSize = self.imageView.image.size;
self.imageView.frame =
CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
}
#end
When I run the app, the image is not scrolled. Doing all the same with auto layout turned off (with struts and springs), I have working scrolling.
I guess the problem is with constraints. Could anybody help me, please?
I just encountered the same issue in a tutorial that I was updating. I attempted programmatically deleting constraints, cursing, and banging my head against the wall - no luck.
About 5 minutes ago, however, I tried something that had fixed another issue I encountered, and, ta da! UIScrollView is working again! The solution was to move the old code that sets the UIScrollView contentSize property into an implementation of viewDidAppear, rather than viewDidLoad:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.theScroller.contentSize=CGSizeMake(200.0,2000.0);
}
I hope this helps someone else encountering some of the headaches that have appeared with Auto Layout.
Autolayout can be very confusing at first. You actually don't want to set the contentSize of the scrollview anywhere. With a pure autolayout approach the scrollview sets its own content size. See the section on autolayout and UIScrollView in the iOS 6 release notes:
The constraints on the subviews of the scroll view must result in a
size to fill, which is then interpreted as the content size of the
scroll view. (This should not be confused with the
intrinsicContentSize method used for Auto Layout.)
Note that this means that the constraints on the subviews of the scrollview must set explicit widths and heights and not use widths that vary based on aspects of the scrollview.
The second error here is that you set the frame of the UIImageView to the size of the image. With autolayout this is also unnecessary. The UIImageView actually has an intrinsicContentSize which is the size of the underlying image. (To change this you should set constraints for width and height with a high priority) That means that with auto layout to place an image in a scrollview and have it scroll the correct code should be the following:
** nothing at all!!! **
But theres still something you need to watch out for that could cause you to have an image that appears not to scroll and the hint is in the aforelinked release notes:
Note that you can make a subview of the scroll view appear to float
(not scroll) over the other scrolling content by creating constraints
between the view and a view outside the scroll view’s subtree, such as
the scroll view’s superview.
i.e. if you set constraints in interface builder and constrain the image view to a view above the scrollview in the hierarchy it will affect how the view appears to scroll. Mad!
Happy Coding...

Setting size property in UIScrollview

I would like to create a scrollview inside of another view. I put a UIScrollview element in IB and declared a UIScrollview in my view controller file that is associated with the main view. I also declared it a property in the view controller header file and synthesized in the corresponding implementation file.
Do I set the size of the scrollview in the app delegate or in the view controller? If I set it in view controller do I still have to do the allocation and initialization commands for that instance? Or do I rely on the getter and setter methods that exist as a result of the scrollview being a property?
I should add that I only want the scrollview to occupy a part of the main view.
Here's my viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
[scrollView setFrame:CGRectMake(0, 44, 768, 1000)];
[scrollView setContentSize:CGSizeMake(768, 1000)];
// Do any additional setup after loading the view, typically from a nib.
}
The actual size of the UIScrollview in IB is 768 by 804, there should be a vertical scrollbar present (some of the UI elements in the scrollview are clipped, so there should definitely be a scrollbar if this view is set up correctly.)
Yes you can set the frame property of the scrollView instance using setFrame.
i.e. irrespective of what frame size you have defined in IB, using [scrollView setFrame:CGFrameMake()]; you can redefine the exact width, height & x, y coordinates.
In fact this is how one goes about creating a dynamic view in iOS.
Once you are exiting this view entirely make sure you dealloc & release this IB instance since it would have been defines as retain.