0

I've been trying to interpret the lessons from CS193P, and have a few questions.

I'm building views in code, the way I do it is I have a UIView subclass where I put all the views in place in the init method. This class is initialized by the ViewController.

The question is then, what is the right approach from here - say i want to animate a button I placed at 0,0 to 100,100. I'd like to animate it from the ViewController, but i don't like the fact that i set the 0,0 position in the UIView class (in the initializer) and now i am setting a new position in the ViewController. I'd prefer there would be just one place knowing about the actual (x,y) positions of my views.

How am i supposed to go about this?

  1. Move the positions in the initializer to the ViewController
  2. Put a method in my UIView "-(void)AnimateToSecondPosition" where the actual "second position" is then up to the view?
  3. Just let it go. It seems like this would be the right approach if i had placed the button in interface builder - i consider interface builder to be the view then...

Or maybe even a fourth option?

Please help me understand it better and not just give me the right answer ;)

I'd like to be able to compare my approach in some way to how you would do it using interface builder, so each of my views are public and accessable from the controller - this way i believe i could easily start using interface builder instead if i wanted, without changing the controller code, just hooking up the outlets.

I'm guessing the case would be the same for disabling, hiding and doing other things with the views.

Thanks in advance.

Lyck
  • 691
  • 1
  • 6
  • 18

2 Answers2

0

You can add an -setButtonFrameToSecondPosition to the view subclass, which simply updates the frame of the button, and then call that from the view controller via one of the +[UIView animate:...] methods.

Stefan Fisk
  • 1,563
  • 13
  • 19
  • wouldn't this be wrong? I know it's possible, but this way the position is the views responsibility? – Lyck Jan 25 '14 at 15:49
  • It all really depends on how you want to structure your code, and there's a lot of factors to consider if you don't already have a style that you prefer. For example, what does the animation itself represent? If it is in response to a state change in the view, then possibly all you'd want is a state property which when set performs the animation. – Stefan Fisk Jan 25 '14 at 15:51
0

If you want to create a new View programmatically you should generally instantiate it in your View Controller using its designated initialiser:

 UIView *testView = [[UIView alloc]initWithFrame:myFrame];

If you create a custom view it's totally fine and correct to put some configuration code in the init method, but it's your ViewController that should be in charge of deciding what to do with this view - it is his job! Using the MVC the View and the Model should never communicate directly (as you definitely learned in the first lesson of CS193P).

Therefore the same apply to the animations. You should animate the Views within your ViewController and not implement the animation in the View itself.

Therefore in my opinion you "second position" should be setup by the VC - if this has to be done when something happens to the view (e.g. someone pressing a UIButton) you should set a target/action to your VC and handle this within your VC.

ADDED: Regarding building UIViews in the Interface Builder I don't know what you mean by "and let them go". Interface builder will create the views and add them to the specific superviews at runtime - as you can see in the example below you control the view hierarchy graphically on the left. For instance in this case there is a UIView (which I coloured green for clarity) and two buttons. One is a subview of the main view while the other is a subview of the green UIView. Storyboard Example

Once your ViewController is loaded the view hierarchy is automatically loaded to self.view - in fact if you run the following code in your VC when it is loaded you will see the list of self.views subviews in your console.

for (UIView *view in self.view.subviews){
    NSLog("%@", [view description]);
}

If you know already that you need to change some attributes of a specific UIView you setup via Interface Builder (e.g. we know we want to change programmatically the color of the green UIView in the example above) you should create an outlet which allows you to have a reference to that view in your code. You do it by crtl-drag from the storyboard to your ViewController code - see the example below.

Create Outlet 1 Create Outlet 2 Create Outlet 3

When you have done that you can refer in code to this as any other property, with the difference that it has been created by Interface Builder.

Hope this helps.

tanz
  • 2,557
  • 20
  • 31
  • So what do you consider to be "configuration code"? This is the positions, states, targets and other properties of the subviews right? But say i had a button that should be hidden if a property in my model is false and shown if the property is true. This would mean i hide the button in my viewcontroller after the init method is called, in case it should be hidden, right? – Lyck Jan 25 '14 at 15:54
  • And how is it comparable to the way it would work using interface builder? – Lyck Jan 25 '14 at 15:55
  • I was referring to a custom UIView - as an example let's say you want to build a special view that shows a shany silver gradient. UIButton doesn't do that so you need to write your own UIView (maybe subclassing UIButtton) and you can put in the UIView init the configuration code needed. – tanz Jan 25 '14 at 17:51
  • Regarding using the UIViews and specifically the UIButton you do it in VC and you setup their properties there. Load the button and set its hidden to YES in the ViewDidLoad of the VC if you want it hidden at the beginning. In the case of interface builder - you can simply tick the hidden checkbox in the UI - it should be on the right if you select the button. Hope it helps. – tanz Jan 25 '14 at 17:54
  • I was hoping for a more cut-throat answer :( I am initializing the view with a couple of UIButtons, some labels and some textfields, as i am reading your response i should go with options 3, and then try to find my own "style", as Stefan mensions. Would it be preferable to have the CGRects of the subviews defined somewhere, since it's the starting position of my subviews? – Lyck Jan 26 '14 at 04:16
  • I am not sure what do you mean by "let them go" in the third option. I updated my answer. – tanz Jan 26 '14 at 12:10
  • Letting it go is referring to how i describe that "I'd prefer there would be just one place knowing about the actual (x,y) positions of my views." So By letting it go i mean just accept that the first positioning of a subview is done in the view and later positioning is done by the viewcontroller. So i will be doing the same going forward. Thanks. I'm accepting the first part of your answer, sorry you did all the work describing how to do it using IB, i was asking about how to use the pattern correctly and not how to code it. – Lyck Jan 26 '14 at 18:29