正确的加载UIView子类的Nib的方法

时间:2013-03-14 09:51:23

标签: iphone ios objective-c uiview xib

我知道之前已经问过这个问题,但答案是矛盾的,我很困惑,所以请不要激怒我。

我想在我的应用程序中拥有一个可重用的UIView子类。我想用nib文件描述接口。

现在让我们说它是一个加载指示器视图,其中包含一个活动指示器。我希望在某个事件上实例化此视图并激活到视图控制器的视图。我可以用编程方式描述视图的界面没问题,以编程方式创建元素并在init方法中设置它们的框架等。

我怎么能用笔尖做到这一点?维护界面构建器中给出的大小,而不必设置框架。

我已经设法这样做,但我确定它是错的(它只是一个带有选择器的视图):

 - (id)initWithDataSource:(NSDictionary *)dataSource {
        self = [super init];
        if (self){
            self = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"%@", [self class]] owner:self options:nil] objectAtIndex:0];
            self.pickerViewData = dataSource;
            [self configurePickerView];
        }
        return self;
    }

但我覆盖了自己,当我实例化它时:

FSASelectView *selectView = [[FSASelectView alloc] initWithDataSource:selectViewDictionary];
    selectView.delegate = self;

    selectView.frame = CGRectMake(0, self.view.bottom + 50, [FSASelectView width], [FSASelectView height]);

我必须手动设置框架而不是从IB中拾取它。

编辑:我想在视图控制器中创建此自定义视图,并有权控制视图的元素。我不想要一个新的视图控制器。

由于

编辑:我不知道这是不是最佳做法,我确定不是,但这就是我做的方式:

FSASelectView *selectView = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"%@",[FSASelectView class]] owner:self options:nil] objectAtIndex:0];
    selectView.delegate = self;
    [selectView configurePickerViewWithData:ds];
    selectView.frame = CGRectMake(0, self.view.bottom + 50, selectView.width, selectView.height);
    selectView.alpha = 0.9;
    [self.view addSubview:selectView];
    [UIView animateWithDuration: 0.25 delay: 0 options:UIViewAnimationOptionAllowUserInteraction |UIViewAnimationOptionCurveEaseInOut animations:^{
                            selectView.frame = CGRectMake(0, self.view.bottom - selectView.height, selectView.width, selectView.height);
                            selectView.alpha = 1;
                        } completion:^(BOOL finished) {
                        }];

正确的做法仍然需要

是否应该使用视图控制器和带有nib名称的init完成?我应该在代码中的某些UIView初始化方法中设置nib吗?或者我做得好吗?

6 个答案:

答案 0 :(得分:128)

MyViewClass *myViewObject = [[[NSBundle mainBundle] loadNibNamed:@"MyViewClassNib" owner:self options:nil] objectAtIndex:0]

我正在使用它来初始化我可以使用的可重用自定义视图。


请注意,您可以在那里使用“firstObject”,它更清洁一点。 “firstObject”是NSArray和NSMutableArray的一个方便方法。

这是加载xib以用作表头的典型示例。在你的文件YourClass.m

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    return [[NSBundle mainBundle] loadNibNamed:@"TopArea" owner:self options:nil].firstObject;
}

通常,在TopArea.xib中,您可以点击文件所有者,然后将文件所有者设置为YourClass 。然后实际上在YourClass.h中 你将拥有IBOutlet属性。在TopArea.xib中,您可以将控件拖到这些商店。

不要忘记在TopArea.xib中,您可能必须点击“查看”本身并将其拖到某个插座,以便在必要时控制它。 (非常值得一提的是,当您为表格单元格行执行此操作时,您必须这样做 - 您必须将视图本身连接到代码中的相关属性。)

答案 1 :(得分:39)

如果您想让CustomView及其xibFile's Owner保持独立,请按以下步骤操作

  • File's Owner字段留空。
  • 点击xib的{​​{1}}文件中的实际视图,并将其CustomView设置为Custom Class(自定义视图类的名称)
  • 在自定义视图的CustomView文件中添加IBOutlet
  • 在自定义视图的.h文件中,点击查看并进入.xib。在这里,您将在Connection Inspector文件
  • 中定义所有IBOutlet
  • 将他们与各自的观点联系起来。

.h课程的.m文件中,覆盖CustomView方法,如下所示

init

现在,当您要加载-(CustomView *) init{ CustomView *result = nil; NSArray* elements = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass([self class]) owner:self options: nil]; for (id anObject in elements) { if ([anObject isKindOfClass:[self class]]) { result = anObject; break; } } return result; } 时,请使用以下代码行 CustomView

答案 2 :(得分:25)

按照以下步骤

  1. 创建一个名为MyView .h / .m的类UIView
  2. 创建一个名称相同的xib MyView.xib
  3. 现在将文件所有者类从xib中的UIViewController更改为NSObject。见下图 enter image description here
  4. 将文件所有者视图连接到您的视图。见下图 enter image description here

  5. 将您的视图类更改为MyView。与3相同。

  6. 放置控件创建IBOutlets。
  7. 以下是加载视图的代码:

    UIViewController *controller=[[UIViewController alloc] initWithNibName:@"MyView" bundle:nil];
    MyView* view=(MyView*)controller.view;
    [self.view addSubview:myview];
    

    希望它有所帮助。

    <强>澄清

    UIViewController用于加载您的xib以及UIViewController实际上MyView中已在MyView xib中指定的视图。

    <强>演示 我做了一个演示抓取here

答案 3 :(得分:9)

回答我自己的问题大约2年或者什么年后,但......

它使用协议扩展,因此您可以在没有任何额外代码的情况下完成所有类。

/*

Prerequisites
-------------
- In IB set the view's class to the type hook up any IBOutlets
- In IB ensure the file's owner is blank

*/

public protocol CreatedFromNib {
    static func createFromNib() -> Self?
    static func nibName() -> String?
}

extension UIView: CreatedFromNib { }

public extension CreatedFromNib where Self: UIView {

    public static func createFromNib() -> Self? {
        guard let nibName = nibName() else { return nil }
        guard let view = NSBundle.mainBundle().loadNibNamed(nibName, owner: nil, options: nil).last as? Self else { return nil }
        return view
    }

    public static func nibName() -> String? {
        guard let n = NSStringFromClass(Self.self).componentsSeparatedByString(".").last else { return nil }
        return n
    }
}

// Usage:
let myView = MyView().createFromNib()

答案 4 :(得分:8)

在斯威夫特:

例如,您的自定义类的名称为InfoView

首先,您可以像这样创建文件InfoView.xibInfoView.swift

import Foundation
import UIKit

class InfoView: UIView {
    class func instanceFromNib() -> UIView {
    return UINib(nibName: "InfoView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! UIView
}

然后将File's Owner设置为UIViewController,如下所示:

enter image description here

将您的View重命名为InfoView

enter image description here

右键点击File's Owner并将view字段与InfoView

相关联

enter image description here

确保班级名称为InfoView

enter image description here

在此之后,您可以将操作添加到自定义类中的按钮,而不会出现任何问题:

enter image description here

MainViewController中使用此自定义类:

func someMethod() {
    var v = InfoView.instanceFromNib()
    v.frame = self.view.bounds
    self.view.addSubview(v)
}

答案 5 :(得分:2)

您可以使用视图控制器初始化xib并使用viewController.view。或者按照你的方式去做。仅将UIView子类作为UIView的控制器是一个坏主意。

如果您的自定义视图中没有任何插座,则可以直接使用UIViewController类对其进行初始化。

更新:在您的情况下:

UIViewController *genericViewCon = [[UIViewController alloc] initWithNibName:@"CustomView"];
//Assuming you have a reference for the activity indicator in your custom view class
CustomView *myView = (CustomView *)genericViewCon.view;
[parentView addSubview:myView];
//And when necessary
[myView.activityIndicator startAnimating]; //or stop

否则你必须自定义UIViewController(使其成为文件的所有者,以便正确连接插座)。

YourCustomController *yCustCon = [[YourCustomController alloc] initWithNibName:@"YourXibName"].

您想要添加可以使用的视图的任何位置。

[parentView addSubview:yCustCon.view];

然而,在加载xib时将另一个视图控制器(已经用于另一个视图)作为所有者传递不是一个好主意,因为控制器的视图属性将被更改,当您想要访问原始视图时,没有参考。

编辑:如果您已将文件所有者设置为同一主UIViewController类的新xib并将view属性绑定到新的xib视图,则会遇到此问题。

即;

  • YourMainViewController - manage - mainView
  • CustomView - 需要在需要时从xib加载。

下面的代码将在以后引起混淆,如果你在视图中写入YourMainViewController的加载。这是因为此时self.view将引用您的自定义视图

-(void)viewDidLoad:(){
  UIView *childView= [[[NSBundle mainBundle] loadNibNamed:@"YourXibName" owner:self options:nil] objectAtIndex:0];
}