iphone - 多个 UIViewController 子类中的相同 UIView 子类?

标签 iphone ios uiview uiviewcontroller interface-builder

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

我的意思是,我希望能够将一个 UIView 拖到每个 UIViewController 的 View 上,并将这个拖拽的 UIView 的类重命名为 CustomView,然后 CustomView 中的所有元素都会显示出来...这可能吗?

最佳答案

根据你的问题和你对高度咖啡因的回答——他的回答是正确的,但我认为可能与你的问题略有偏差——我认为你希望能够在 Interface Builder 中以图形方式设计一个 View (所以,你还没有编写自定义 UIView 子类,您只是以某种方式安排了一些 UIView,因此它们都是另一个 View 的子级),然后通过某种间接引用将其嵌入到多个 View Controller 中,这样您不是复制和粘贴相同的用户界面元素,如果您在一个地方进行更改,那么该更改将在所有地方生效?

据我所知,Interface Builder 或 Xcode 4 中没有内置工具可以实现这一点。 XIB 是纯数据,而 UIView 不具备处理文件外引用的智能。

你可以做的是设计你想在一个 XIB 中使用的 View ,称为 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 放入您希望可重用 View 所在的位置,并将“类”设置为“ReusableViewTemplate”或您所称的任何名称。

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

编辑:对此的进一步思考。我创建了一个 example project (目前在一个通用的文件共享网站上,所以可能不会永远存在)带有一个 ReusableView 类,为了示例的目的,它包含一个段 View 和一个按钮,看起来像这样:

@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):

@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

最终效果是,如果 View Controller 在 XIB 中具有 ReusableView 类型的 UIView,它会在运行时插入 ReusableVew.xib 的内容。如果它在 Interface Builder/Xcode 4 中将自己连接为 ReusableView 的委托(delegate)并实现:

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

然后它从嵌入式 View 中获取消息。

在 Objective-C 中,这是通过使用 NSObject 的固有能力转发选择器(从 iOS 4 开始)或调用(在早期版本中,成本更高)而实现的,它没有实现而不是允许发生异常。

关于iphone - 多个 UIViewController 子类中的相同 UIView 子类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6669938/

相关文章:

iphone - 我怎样才能得到iPhone中两个时间之间的差异?

ios - 比较所有可能情况下的两个枚举

ios - 如何在 Swift 中保存 CoreGraphics 绘图

iPhone 5 View 框架变化

iphone - 应用程序在内存不足后关闭。里面的仪器截图

iphone - iPhone 中的高级搜索实现?

ios - 如何在钛合金应用程序中在 iOS 谷歌地图上显示方向

ios - 如何在处理通知时禁止 OneSignal 打开 WebView

ios - 将 UIView.transform 设置为任意平移 CGAffineTransform 不会执行任何操作

iphone - 如何在屏幕上显示所有触摸以演示 iPhone 应用程序?