Interface-Builder: “combine” NSView-class with .xi

2020-05-27 23:05发布

I'd like to set up a custom NSView in Interface-Builder, but I don't get it to work for OSX.

In my ViewController's .xib, I added a custom view and set the Class to MyCustomView. I created MyCustomView.h, MyCustomView.m and MyCustomView.xib.

In MyCustomView.xib, I set the Class to MyCustomView as well. In MyCustomView.m, - (void)awakeFromNib is called, but - (id)initWithCoder:(NSCoder *)aDecoder and - (id) awakeAfterUsingCoder:(NSCoder*)aDecoder aren't.

What I'd like to achieve is that in my ViewController, the view I added is "filled" with the view I set up in MyCustomView.xib. What's the best way to do that?

EDIT: I don't think I was clear enough...

I've got my ViewController containing a Custom View called MyCustomView.

enter image description here

This view should be of type MyCustomView, where

MyCustomView.h MyCustomView.m MyCustomView.xib

exists. I already set the File's Owner of MyCustomView.xib to MyCustomView and I already set the CustomView in my ViewController to MyCustomView - but it doesn't work.

If I do it with

- (void)awakeFromNib {
    NSString* nibName = NSStringFromClass([self class]);
    NSArray* topLevelObjects;
    [[NSBundle mainBundle] loadNibNamed:nibName
                              owner:nil
                    topLevelObjects:&topLevelObjects];

    NSView* view = topLevelObjects[0];
    [view setFrame:[self bounds]];
    [self addSubview:view];
}

I only get a view of type NSView, not MyCustomView... Is there no easy way to tell the ViewController.xib that it's a MyCustomView?

EDIT 2: I uploaded a simple project

At https://dl.dropboxusercontent.com/u/119600/Testproject.zip you find a simple project with the MyCustomView (not in a ViewController but in the window.xib) - but it doesn't show the button which is in MyCustomView.xib. I'd like to achieve exactly that - what's the simplest, best way?

2条回答
做自己的国王
2楼-- · 2020-05-27 23:17

EDIT - apologies, my existing answer failed to take into account the need to connect outlets and actions. This way should do it...

Given the files...

MyCustomView.h
MyCustomView.m
MyCustomView.xib

In MyCustomView.h

  • declare IBOutlets for your interface elements. You need at least one, to hold a pointer to the top-level view in the xib file

    @property (nonatomic, strong) IBOutlet NSView *view;

In MyCustomView.xib

  • ensure that there is only one top-level view
  • set file's owner class to MyCustomView in the Identity Inspector
  • ensure that the top-level view is set to the default NSView class.
  • now you can connect IBOutlets declared in MyCustomView.h to interface objects in the xib file. At very least you need to connect up the top-level view to your view outlet.

In MyCustomView.m:

- (id)initWithFrame:(NSRect)frame
{
    NSString* nibName = NSStringFromClass([self class]);
    self = [super initWithFrame:frame];
    if (self) {
        if ([[NSBundle mainBundle] loadNibNamed:nibName 
                                          owner:self 
                                topLevelObjects:nil]) {
            [self.view setFrame:[self bounds]];
            [self addSubview:self.view];
            [self.myCustomButton setTitle:@"test success"];
        }
    }
    return self;
}

In your window's xib file, add a custom NSView and change it's class to MyCustomView.

in OSX prior to 10.8 the method loadNibNamed was a class method - use it instead if you need backwards compatibility, but it is deprecated now:

[NSBundle loadNibNamed:@"NibView" owner:self]

Note that MyCustomView.xib's view is NOT MyCustomView's view, but the sole subview of it's view (this is similar to the way a tableViewCell possesses a single contentView).

In the project sample you have posted, you need to make the following changes:

  • in MyCustomView.h
    . add an NSView property

  • in MyCustomView.xib:
    . change the top-level view from MyCustomView custom class to NSView (the default)
    . set the File's Owner to MyCustomView.
    . connect IBOutlets from File's owner's view and myCustomButton to interface view and button
    . for testing make the view a lot smaller and push the button up to the top right (you won't see it in your window as it is here)

  • in MyCustomView.m:
    . replace all of your implementation code with the initWithFrame method here

查看更多
劫难
3楼-- · 2020-05-27 23:36

In order to load a custom subclass of a view or a control (or any other class that can be used in Interface Builder for that matter), you need to add the base version (NSView in your case, and as you have done), then select that object in the window and go to the Identity Inspector (Cmd-Opt 3).

Instead of the pre-defined value for Class (NSView, in your case), type in the name of your custom subclass. Voilà!

A small detail related to the IB UX is that you'll probably have to move the focus from the input field in order for that change to be registered when you build and run the app.

查看更多
登录 后发表回答