几个UIViewController子类中的UIView子类是一样的吗?

时间:2011-07-12 19:28:58

标签: iphone ios uiview uiviewcontroller interface-builder

我有几个UIViewControllers。我想在所有这些子集中使用相同的UIView子类(它位于现有的UIViewController的视图之上)。这可以使用Interface Builder吗?

我的意思是,我希望能够将UIView拖到每个UIViewController的视图上,并将这个拖动的UIView的类重命名为CustomView,并且CustomView中的所有元素都会显示出来......这可能吗?< / p>

2 个答案:

答案 0 :(得分:2)

是的,这是可能的。正如您可以在项目中拥有(例如)多个UIViewController,每个UIImageView作为一个视图,您可以对自己的UIView子类执行相同操作。

答案 1 :(得分:2)

基于您的问题以及您对高度咖啡因的回答 - 他的回答是正确的,但我认为可能与您的要求略有不同 - 我认为您希望能够在Interface Builder中以图形方式设计视图(所以,你没有编写自定义的UIView子类,你只是以某种方式安排了一些UIViews,以便它们都是另一个视图的子项),然后通过某种间接引用将它嵌入到几个视图控制器中,这样你就可以了'不要复制和粘贴相同的用户界面元素,如果你在一个地方进行了更改,那么这个更改会在所有地方生效吗?

据我所知,Interface Builder或Xcode 4中没有用于实现这一目标的内置工具。 XIB是纯数据,UIViews没有智能来处理文件外引用。

您可以做的是设计要在一个XIB中使用的视图,称为ReusableView.xib,然后编写一个类似于以下内容的自定义UIView子类:

@implementation ReusableViewTemplate

- (id)initWithCoder:(NSCoder *)aDecoder
{
    // initialise ourselves normally
    self = [super initWithCoder:aDecoder];

    if(self)
    {
        // load everything in the XIB we created
        NSArray *objects = [[NSBundle mainBundle] 
                            loadNibNamed:@"ReusableView" owner:self options:nil];

        // actually, we know there's only one thing in it, which is the
        // view we want to appear within this one
        [self addSubview:[objects objectAtIndex:0]];
    }

    return self;
}

@end

然后,在你的NIB中放入一个你想要可重用视图的UIView,然后将'class'设置为'ReusableViewTemplate'或你称之为的任何内容。

如果打开ReusableView XIB并将父视图的类型设置为ReusableViewTemplate,则可以连接任何UIControl(例如按钮或开关)以连接到那里。您可能希望为可重用的视图模板定义一些自定义协议,并在任何使用可重用视图的视图控制器中捕获viewDidLoad,以便设置适当的委托。

编辑:进一步的想法。我创建了一个example project(当前在一个通用的文件共享站点,所以可能无法永存),使用ReusableView类,为了示例的目的,包含一个段视图和一个按钮,看起来像这样: / p>
@implementation ReusableView

/*

    initWithCoder loads the relevant XIB and adds its
    only object, which is a UIView, as a subview of this
    one. If you don't like the double hierachy, you
    could just have a list of views in the XIB and
    addSubviews:, but then it'd much more difficult to
    edit the thing graphically. You could strip the top
    view programmatically, but this is just a simple
    example, so...

*/
- (id)initWithCoder:(NSCoder *)aDecoder
{
    // initialise ourselves normally
    self = [super initWithCoder:aDecoder];

    if(self)
    {
        // load everything in the XIB we created
        NSArray *objects = [[NSBundle mainBundle] 
                                loadNibNamed:@"ReusableView"
                                owner:self
                                options:nil];

        // actually, we know there's only one thing in it, which is the
        // view we want to appear within this one
        [self addSubview:[objects objectAtIndex:0]];
    }

    return self;
}

@synthesize delegate;
@synthesize segmentedControl;
@synthesize button;

/*

    NSObject contains machinery to deal with the possibility
    that a class may be sent a selector to which it doesn't
    respond.

    As of iOS 4, forwardingTargetForSelector: can be used to
    nominate an alternative target for the selector quickly.

    In previous versions of iOS, or in iOS 4 if you don't
    respond to forwardingTargetForSelector:, you may take
    delivery of the problematic invocation and deal with it
    yourself.

    Dealing with the invocation costs more than providing
    a forwarding target for the selector, so its worth having
    both.

    If you're only targeting iOS 4 or above, you needn't
    keep the implementation of forwardInvocation: below.

    What we're doing is declaring a bunch of IBActions so
    that we can wire changes up to them in Interface Builder.
    By failing to implement them and providing the delegate
    as the thing to talk to for any selectors we don't know,
    we're allowing those wirings to be as though assigned
    to the delegate.

*/
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return delegate;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setTarget:delegate];
    [anInvocation invoke];
}

@end

使用界面:

@interface ReusableView : UIView 
{

    IBOutlet id delegate;

    IBOutlet UISegmentedControl *segmentedControl;
    IBOutlet UIButton *button;

}

@property (nonatomic, assign) id delegate;

@property (nonatomic, assign) UISegmentedControl *segmentedControl;
@property (nonatomic, assign) UIButton *button;

/*

    NB: we're not actually going to implement these. We're
    declaring them for the benefit of Interface Builder / Xcode 4.

    What we'll actually do is, any time we receive a selector
    we don't implement, hand it off to the delegate. So it's a
    quick way of avoiding writing any glue code to pass messages
    from this little reusable view to its delegate.

    A better alternative could define a formal protocol that
    forwards both the changed control and self from the
    reusable view to its delegate. But that's obvious and
    verbose, so has been omitted for the purposes of example.

    The implementation as stands will generate compiler warnings,
    but such is life. To get rid of the warnings, comment out
    the two following lines, but only AFTER you've wired
    everything up in Interface Builder / Xcode 4. They're left
    uncommented here to help draw attention to the point about
    selector/invocation forwarding that you'll see in the
    @implementation.

    !!!!!!!!!!!!!!!

            HENCE:

            delegates MUST implement the following methods.

    !!!!!!!!!!!!!!!

    We could work around that by checking at runtime whether
    the actual delegate implements them and forwarding to
    a dummy object that implements them to do nothing otherwise,
    but that's slightly beyond the point of the example.

*/
- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;

@end

净效果是如果视图控制器在XIB中具有类型为ReusableView的UIView,它将获取在运行时插入的ReusableVew.xib的内容。如果它在Interface Builder / Xcode 4中作为ReusableView的委托自行连接并实现:

- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;

然后它从嵌入的视图中获取消息。

这在Objective-C中非常简单和非常巧妙地实现,它使用NSObject的固有能力转发选择器(从iOS 4开始)或调用(在早期版本中,以更高的成本)它没有实现而不是允许发生例外。