How should I draw on ViewController's default View? - cocoa-touch

XCode 4.2 (the only version of XCode I've ever used) creates a ViewController with a default View property.
I cannot see the code for this default View so I cannot draw on it (because I cannot access drawRect). Is that correct?
Assuming answer to the above is that I cannot draw. If I want to draw on the window should I:
Add a subview to the default View and then draw (via drawRect) on the subview? or
Replace the default View with one that I create and can therefore draw on via drawRect?
This is not a question of how to do this, I want to know what would be the best way. Thanks.

If you need to do custom drawing in you view, then you should define your own custom UIView class, where you override drawRect to do the custom drawing.
Now, wether you follow either approach 1. or 2. depends on what your app does. Both are perfectly reasonable.
Say, for example, that you would like to do your custom drawing, but also show some kind of controls (e.g. to clear the drawing, to reset it, and so on), then I think it could be a better design if you have a root view that you add both the custom view and the other view to as subviews. But this is just an example and it depends on what you are trying to accomplish.
Hope this helps a bit...

Related

Handling NSLayoutConstraints from code properly

I started to use AutoLayout in my latest project, and I am stuck at some point. I use a content view controller, which adds other view controllers as sub view controllers, and their views as subviews aswell. Everything is fine, except that my sub controllers' view have wrong view sizes.
One of my sub view controllers sets up something like a slider, which has a knob. The initial position of this know depends from the actual size of this view, which is not fix, because I reuse it in many forms. Everything is set up with AutoLayout. Of course, because the value of this slider is coming from another part of code, the position of the know can be described only something like this:
self.knobVerticalPositionConstraint.constant = topPos + height * percentage;
where height is depending on the size of the slider view itself.
The problem is, that when the whole thing gets displayed, parts of my UI have wrong sizes. I even have a wrong view size in the sub controller's -viewDidAppear.
I think this is a problem of how I wrote my code. Maybe not everything is in it's place. I have read this article, which promises a clean and elegant way to solve this type of issues, but it is never revealed:
http://doing-it-wrong.mikeweller.com/2013/06/ios-app-architecture-and-tdd-1.html
I have read the whole Internet, but I didn't found anything like this. It is full of stuff for beginners and first step guides about "How to use AutoLayout", but I never found any advanced tips.
So my specific question is: do you have any best practices, how to assemble a View Controller–View pair which uses AutoLayout from code? Where do you set up your constraints? Where do you update constraint constants like mine, which depends on the calculated values of the constraint equalation system? What code goes to the View and what to the controller? I'd be glad if you could share me some tips to solve this issue.
I have recently completed the migration of my first (and so far only) iOS project to Auto Layout. The stuff below is roughly what I have taken away from my efforts. It's not much, but since I wanted to write it down for myself anyway, here you go, maybe it helps.
Static constraints that never change go into a view controller's loadView override, or in a view's initializer (or some sub-method thereof)
Dynamic constraints which depend on other values calculated by the layout system go into a view controller's viewDidLayoutSubviews override, or in a view's layoutSubviews override (in the latter case it makes sense to call [super layoutSubviews] first to get updated values that the dynamic constraint can be based on).
After a change to a dynamic constraint, it may be necessary to tell the layout system that something changed. For instance, in a view's layoutSubviews override I call [super layoutSubviews] a second time after the constraint change so that the update is effective immediately
A view controller can also override updateViewConstraints, and a view can override updateConstraints, but I have not used these so far.
There are many other events that might trigger an update of dynamic constraints (e.g. keyboard events), but this is beyond the scope of best practices.
Some general guidelines:
Constraints are installed by the view controller or view who sets up the view hierarchy and therefore knows about and is responsible for the layout of the view hierarchy. Although this rule is very basic, it sometimes pays to keep it in mind.
The translatesAutoresizingMaskIntoConstraints property of a UIView is set by that view controller which installs constraints for that UIView
A view controller therefore does not set the translatesAutoresizingMaskIntoConstraints property of its own root view. Instead, this is the responsibility of the parent view controller.
View controller properties related to bar handling in iOS 7:
edgesForExtendedLayout, usually set to UIRectEdgeNone
topLayoutGuide and bottomLayoutGuide
make all bars opaque (by default all bars are translucent in iOS 7), which would then allow the property extendedLayoutIncludesOpaqueBars to kick in
And some traps:
Don't install constraints in UIWindow. When I tried this I had trouble when dismissing a VC after it was presented modally.
The view controller properties topLayoutGuide and bottomLayoutGuide should only be used inside a view controller's override of viewDidLayoutSubviews, and after they are used to install constraints one must invoke [self.view layoutSubviews]. This advice is actually from Apple's documentation of those two properties. Not following the advice may lead to weird layout issues (it happened to me).
If a view controller's view hierarchy contains one or more scroll views (e.g. table views), and there are unexpected layout results, then the view controller property automaticallyAdjustsScrollViewInsets is probably playing a role. Setting it to NO might help.
My personal favourite ressource, by the way, for understanding Auto Layout was and still is this section from the book "Programming iOS 6".

What is the proper way to deal with changing a single UIView within a storyboard scene

Lets say I have a scene which includes a UIView container on the top half of the screen, and a UIView container on the bottom half of the screen and a few buttons at the very bottom of the screen.
Basically the bottom container will always display static text while the buttons across the bottom will change the content of the top container which may include an image, more buttons, or more text depending on what button is pressed on the bottom. Also each time a bottom button is pressed the top container is transitioned to the new view with a flip from bottom transition.
I have achieved this purely programmatically, but decided to convert my app to a storyboard file since it makes producing the rest of my app much faster and simpler, plus makes the code not look like a crazy mess.
My limited understanding of storyboards seems to deduce that I would need a separate story board scene for every UIView change, and Apple's coding conventions with storyboards seem to imply that we should use a new ViewController every time you create a new scene. All this adds up to an even bigger mess than I currently have.
Is there a better way of doing this? Am I misunderstanding something? If I am not confused, is there some way to make all these scene and view controller duplication cleaner?
The storyboard editor makes it difficult to do what you're describing, because it doesn't let you edit freestanding views associated with a scene.
I suggest you just create a separate nib (not storyboard) for each of the top-half views. These can exist separate from your storyboard. Your view controller (which is instantiated from the storyboard) can then load whichever nib it needs when a button is pressed, and put the view from the nib into its (the view controller's) top-level view.
There must be a way!
I accidentally opened one one day (see attached image). Although I have no idea how I did it and really really want to know, I cannot reproduce it, nor close it. The UIView opened when I was dragging my connection for the table header view from the Connections Inspector to the list of controls on the left side of the screen (not to the actual UIViewController).
I too am reworking a project with storyboards and have a similar problem with multiple views per UIViewController.
In this case it is a table header. I have other UIViewControllers in the project with the same configuration but I cannot get them to pop up either.

proper ios5 storyboard flow for a constant background / transparent views?

I have one background I want constant to all views; it shouldn't animate out and back to itself. I have another background I want common to another handful of views that layers on top of that one. I could do this cleanly enough by:
a) just having one viewcontroller and managing all the transitions of layered objects within that
b) using separate viewcontollers and managing them programatically
But I don't grok how I can do this with a storyboard proper-like. Do I need to make a custom segue? Is there a certain type of segue it should be, if it's custom (or otherwise)? Is there a best viewcontroller that I do it all inside? (note: there's no "levels" of navigation, tab bar, navbar, etc... though if that's the way to go, with the elements hidden, and that's the "best" way to do it, I suppose that that might be me c)? )
Hope I've explained this well enough. :) I do grok layer transparency, etc, as far as views go....
Thanks!
ETA: After more research, I thought I understood c as the correct answer, (with a nod to set "default" UIViewController background image? ) ~
navigation controller with main background
navigation controller with secondary background elements
subpage 1
subpage 2
subpage 3
other controller
But I'm still hitting a wall. Not grokking the storyboard (IB) way to even add a background to a navigation controller. The number of custom classes I've made and tossed out, now....
See if this is what you need. It is not in storyboard, but should do well enough.
navViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.jpg"]];
This is what I have done (but only with 1 level of nav controller). You can put this code in AppDelegate.m, or maybe subclass UINavigationViewController and change the view's backgroundColor there (and attach it within StoryBoard)
I guess the problem is StoryBoard still has some limitations. And UINavigationViewController is not an interface element, it is a View Controller. It is simply shown as a simulated element in StoryBoard.)

Cocoa Merging Custom Views

Currently, I have an NSStatusItem that, when clicked, shows a custom view below it. The view contains some information and text fields. What I need is for a separate custom view to merge with the first and appear below it, as in further down the screen, not on top or behind the original view. This needs to be a separate view because there are actually several custom view that will be appended depending on what the user does in the first view. I would like to be able to independently add or remove each of these without affecting the others. I've dug through apple documentation but I haven't found anything about putting one custom view inside another programatically.
NSView has an addSubview:positioned:relativeTo: method you can use to add and order views to appear above or below each other. Use superview: to access this method on a container from any of its subviews.
Edit:
Try adding both views to an NSSplitView with a hidden divider. To hide the divider, subclass NSSplitView and override the dividerThickness: method to return 0;

CGContext is being covered by a UIView

I'm not that great with Core Graphics, but I am drawing text on the screen to my CGContext. I am doing this immediately after I add a standard, opaque UIView to my user interface.
Does anyone know why the text I draw after I add my UIView is still at the "bottom" of the user interface?
Thanks in advance.
iOS, like OS X, uses a compositing window manager. Adding and removing UIViews sets their position in the view hierarchy; when and how they're drawn is managed separately. There is no guaranteed relation between when a view is added and when it'll be drawn, and no reason to guarantee one. The content of a view is cached and composited as required from that copy.
If you want to do custom drawing, create a custom UIView subclass, add it to the hierarchy according to where you want it to appear and do your drawing in drawRect: or one of the other override points if you want to render off thread.