开发者

How to Instantiate and Call UIView Subclasses Without Using a Nib

Without using Interface builder or xib files, what is the correct way to instantiate two classes which inherit from UIView such that they can switch between themselves using UIButtons located on the views themselves?

I think this involves setting up a UIViewController from the app delegate and adding two instances of my classes which implement UIView into the controller (perhaps from inside the controller?)

I'm also not sure how to raise events from UIButtons on the custom UIViews to switch the views. I suspect I would need to add a method to the view controller but I'm not sure how to get a reference to the view controller from inside the scope of my UIView.

Also, I'm wondering that,if the use of a UIViewCon开发者_如何学Ctroller is necessary, should the switch method could be in the scope of the main app delegate?

Some code examples would be great!


Your main problem is that you don't conceptually understand the role of UIViewControllers versus UIViews. Most people don't when they first start out.

Views are stupid and ideally, they should be composed of generic objects. They contain virtually none of the logic of the interface. They do not know or care about the existence of other views. The only logic you put in views is logic that pertains to the immediate and generic functioning of the view itself, regardless of the data it displays or the state of other parts of the app. You seldom need to subclass UIView. This is why views can be completely configured in Interface builder without any code.

ViewControllers contain the logic of the interface and connect the interface to the data (but they do not contain or logically manipulate the data.) They are "intelligent" and highly customized. The viewControllers do understand the place of the view in the context of the app. The viewControllers load and configure the views either from nib or programmatically. The viewControllers control when the views are displayed or hidden and it what order. The viewControllers determine what action is taken in response to events and what data gets displayed where.

VictorB's example code shows how this is all done pragmatically. The important thing to note is that the viewController and view are entirely separate objects from two entirely separate classes. There is no overlap and no need to subclass UIView. All the customization is in the controller.

All this is because of the MVC design patter. It decouples the interface from the data model, making them both modular and independent of each other. This makes it easy to design, debug, and reuse each independent module.


If you want to get it done in code, here is an example I just drummed up using lazy loaded UI elements. I'm only making one button here and swapping it between whichever view is active. It's slightly awkward, but it reduces the amount of code necessary to demonstrate this.

I've created two UIViews to represent your custom classes, one with a blue background and one with a red. The button swaps between the two. If you have a unique button already in each of your custom views, you just need to either expose those buttons as properties of your UIView subclasses so your view controller can access them, or add the view controller as a target for the button's action from within your UIView's loading code.

I've tested this code in my simulator and it seems to work fine, but you really should try to understand what's going on here so you can implement it yourself.

ToggleViewController.h:

#import <UIKit/UIKit.h>
@interface ToggleViewController : UIViewController {
    UIView *firstView;
    UIView *secondView;
    UIButton *button;
}
- (void)addButton;
- (void)toggleViews;
@property (nonatomic, readonly) UIView* firstView;
@property (nonatomic, readonly) UIView* secondView;
@property (nonatomic, readonly) UIButton* button;
@end

ToggleViewController.m:

#import "ToggleViewController.h"
@implementation ToggleViewController

// assign view to view controller
- (void)loadView {
    self.view = self.firstView;
}

// make sure button is added when view is shown
- (void)viewWillAppear:(BOOL)animated {
    [self addButton];

}

// add the button to the center of the view
- (void)addButton {
    [self.view addSubview:self.button];
    button.frame = CGRectMake(0,0,150,44);
    button.center = self.view.center;
}

// to toggle views, remove button from old view, swap views, then add button again
- (void)toggleViews {
    [self.button removeFromSuperview];
    self.view = (self.view == self.firstView) ? self.secondView : self.firstView;
    [self addButton];
}

// generate first view on access
- (UIView *)firstView {
    if (firstView == nil) {
        firstView = [[UIView alloc] initWithFrame:CGRectZero];
        firstView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        firstView.backgroundColor = [UIColor redColor];
    }
    return firstView;
}

// generate second view on access
- (UIView *)secondView {
    if (secondView == nil) {
        secondView = [[UIView alloc] initWithFrame:CGRectZero];
        secondView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        secondView.backgroundColor = [UIColor blueColor];
    }
    return secondView;
}

// generate button on access
- (UIButton *)button {
    if (button == nil) {

        // create button
        button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];

        // set title
        [button setTitle:@"Toggle Views" 
                forState:UIControlStateNormal];

        // set self as a target for the "touch up inside" event of the button
        [button addTarget:self 
                   action:@selector(toggleViews) 
         forControlEvents:UIControlEventTouchUpInside];
    }
    return button;
}

// clean up
- (void)dealloc {
    [button release];
    [secondView release];
    [firstView release];
    [super dealloc];
}

@end


Use Interface Builder. It's there for a reason.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜