Silver challenge: positioning a subView within a view


#1

Hello. This is a question about positioning a subView (in this case, the UISegmentedControl) within a view.

In my version of the silver challenge – see below – I fiddled around with setting the UISegmentedControl’s center property. My approach worked, but it seems a bit trial-and-error-ish. Is there an ‘official’ way to make sure that a programatically-created control like this will always end up in a sensible location?

Also… I set up the pointer to my HypnosisView in HypnosisViewController.h as a property. Is that the best place for it, or should I try to create a private variable somewhere within HypnosisViewController.m?

Thanks for your help.

James

[code]- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];

// v is defined as @property (nonatomic, strong) HypnosisView *v in the header file

[self setV:[[HypnosisView alloc] initWithFrame:frame]];

// Set up UISegmentedControl

NSArray *items = [[NSArray alloc] initWithObjects:@"Red", @"Green", @"Blue", nil];
UISegmentedControl *sc = [[UISegmentedControl alloc] initWithItems:items];
[sc addTarget:self action:@selector(setCol:) forControlEvents:UIControlEventValueChanged];

// Position it

CGPoint scCenter;
scCenter.x = frame.size.width / 2;
scCenter.y = [sc bounds].size.height;

[sc setCenter];

// Add the UISegmentedControl as a SubView

[self.v addSubview:sc];

// Set the ViewController's view

[self setView:self.v];

}[/code]


#2

I put this code in the initWithNibName:bundle-method of HypnosisView:

[code]colorControl = [[UISegmentedControl alloc] init];
[colorControl insertSegmentWithTitle:@“Red” atIndex:0 animated:NO];
[colorControl setWidth:75 forSegmentAtIndex:0];

    [colorControl insertSegmentWithTitle:@"Green" atIndex:1 animated:NO];
    [colorControl setWidth:75 forSegmentAtIndex:1];
    
    [colorControl insertSegmentWithTitle:@"Blue" atIndex:2 animated:NO];
    [colorControl setWidth:75 forSegmentAtIndex:2];

    CGPoint center = CGPointMake(self.view.bounds.size.width / 2.0, 30.0);
    CGRect frame = CGRectMake(center.x - 225 / 2, center.y, 225, 50);
    
    [colorControl setFrame:frame];
    
    [self.view addSubview:colorControl];[/code]

So I created the UISegmentedControl, added the segments with a width of 75px each, resulting in a controller that is 225px wide. I used this to determine the placement using the same method that has been used previously in the book.

I’m in no way sure if this is the “official” way or not - I doubt there is one. You will need to determine the center of the view and where to place the subview based on that on a case-to-case basis, I don’t think there is any way to automate that.

As to your other question: There is no need to maintain a pointer to the HypnosisView. I used this code in loadView (Same code that was used in the book):

[code]- (void)loadView {
// Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *v = [[HypnosisView alloc] initWithFrame:frame];

// Set it as *the* view of this view controller
[self setView:v];

}[/code]

So you initialize the view, and pass it to the view controller - The view-controller will take it from there. Unless you need to make some change to the view later, you’re not going to be needing that pointer again. And if you do, you can just create a new pointer when needed.


#3

@Snoldus

Did your implementation work for the color changes? I tried a similar implementation and once I used setView, the view became of type UIView which meant that I could not access setColor that was defined in HypnosisView. I had to go back and implement it as a class variable in order to access it properly and change the view.

@JamesW

I decided to do the same implementation that you did in order to determine the view size. My logic for this decision is that since I pull the size directly from the actual view that was created, a change to the view later on will not render this code problematic due to the static implementation.