web-dev-qa-db-ja.com

Interface Builderで作成したnibファイルを使用してUIViewをロードする方法

私は少し手の込んだことをやろうとしていますが、それは可能であるべきです。だからここにあなたのすべての専門家のための挑戦があります(このフォーラムはたくさんの皆さんのパックです:)。

NavigationContoller(私のQuestionManagerViewController)にロードしたいアンケート「コンポーネント」を作成しています。 "component"は "empty" UIViewControllerです。これは、回答が必要な質問に応じて異なるビューをロードできます。

私がやっている方法は次のとおりです。

  1. Question1ViewオブジェクトをUIViewサブクラスとして作成し、いくつかのIBOutletsを定義します。
  2. (Interface Builderを使用して)Question1View.xib(HERE IS WHERE MY PROBLEM PROBABLY IS)を作成します。 UIViewControllerUIViewの両方をQuestion1Viewクラスに設定しました。
  3. 私は(IBを使って)アウトレットをビューのコンポーネントにリンクさせます。
  4. 私はinitWithNibQuestionManagerViewControllerを次のように上書きします。

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) {
            // Custom initialization
        }
        return self;
    }
    

コードを実行すると、このエラーが発生します。

2009-05-14 15:05:37.152 iMobiDines [17148:20b] ***キャッチされていない例外 'NSInternalInconsistencyException'のためアプリケーションを終了しました、理由: '-[UIViewController _loadViewFromNibNamed:bundle:]は "Question1View"ペン先をロードしましたがビューアウトレットが設定されませんでした。

ViewControllerクラスを作成しなくても、nibファイルを使用してビューをロードする方法があるはずです。

237
Gonso

ペン先を配列として扱うのではなく、ビューにアクセスするより簡単な方法もあります。

1)後でアクセスしたいアウトレットを持つカスタムViewサブクラスを作成します。 - 私の見解

2)あなたがペン先をロードして処理したいUIViewControllerで、ロードされたペン先のビューを保持するIBOutletプロパティを作成します、例えば

myViewController(UIViewControllerサブクラス)内

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(それを合成してあなたの.mファイルに入れるのを忘れないでください)

あなたのペン先(IBYで 'myViewNib.xib'と呼びます)を開き、ファイルの所有者をに設定しますMyViewController

4)これであなたのファイルの所有者アウトレットmyViewFromNibをペン先のメインビューに接続します。

5) MyViewControllerで、次の行を書きます。

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

あなたがそうするようになったらすぐに、あなたのプロパティ "self.myViewFromNib"を呼び出すことはあなたのnibからビューへのアクセスをあなたに与えるでしょう!

223
averydev

皆さん、ありがとうございました。やりたいことをやる方法を見つけました。

  1. 必要なUIViewを使ってIBOutletを作成します。
  2. IBでxibを作成し、好みに合わせてデザインし、次のようにリンクします。ファイルの所有者はクラスUIViewControllerです(カスタムサブクラスはありませんが、実際のもの)。ファイル所有者のビューはメインビューに接続されており、そのクラスは手順1)のクラスとして宣言されています。
  3. コントロールをIBOutletsで接続します。
  4. DynamicViewControllerはそのロジックを実行して、どのview/xibをロードするかを決定できます。決定したら、loadViewメソッドで次のように入力します。

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;
    

それでおしまい!

メインバンドルのloadNibNamedメソッドは、ビューの初期化と接続の作成を行います。

これで、ViewControllerはメモリ内のデータに応じてビューなどを表示できるようになり、「親」画面はこのロジックに煩わされる必要がなくなります。

119
Gonso

いくつかの答えが何を言っているのかよくわかりませんが、次回Googleで検索するときには、この答えをここに含める必要があります。キーワード:「ペン先からUIViewを読み込む方法」または「NSBundleからUIViewを読み込む方法」

これは、ApressiPhone 3のはじめの本(247ページ、「新しいTable View Cellの使用」)からほぼ100%引用したコードです。

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
                                                 owner:self options:nil];
    Blah *blah;
    for (id object in bundle) {
        if ([object isKindOfClass:[Blah class]]) {
            blah = (Blah *)object;
            break;
        }
    }   
    assert(blah != nil && "blah can't be nil");
    [self.view addSubview: blah];
} 

これはUIViewと呼ばれるBlahサブクラス、クラスがBlahに設定されたUIViewを含むBlahと呼ばれるペン先があると仮定します。


カテゴリー:NSObject + LoadFromNib

#import "NSObject+LoadFromNib.h"

@implementation NSObject (LoadFromNib)

+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:classToLoad]) {
            return object;
        }
    }
    return nil;
}

@end

スイフトエクステンション

extension UIView {
    class func loadFromNib<T>(withName nibName: String) -> T? {
        let nib  = UINib.init(nibName: nibName, bundle: nil)
        let nibObjects = nib.instantiate(withOwner: nil, options: nil)
        for object in nibObjects {
            if let result = object as? T {
                return result
            }
        }
        return nil
    }
}

そして使用中の例:

class SomeView: UIView {
    class func loadFromNib() -> SomeView? {
        return self.loadFromNib(withName: "SomeView")
    }
}
69
Dan Rosenstark

カスタムビューの複数のインスタンス、つまりOutlet Collectionを管理する必要がある人のために、@ Gonso、@ AVeryDev、および@Olieの回答を次のようにマージしてカスタマイズしました。

  1. カスタムのMyView : UIViewを作成し、それを必要なXIBのルートUIViewの "Custom Class"に設定します。 custom class

  2. すべてを作成するアウトレットMyViewに必要なもの(ポイント3以降、IBはアウトレットをUIViewControllerに接続し、カスタムビューには接続しないように提案します)。 custom class outlet

  3. UIViewControllerをカスタムビューの "File's Owner"に設定してくださいXIBenter image description here

  4. UIViewControllerに、必要なUIViewsのインスタンスごとに新しいMyViewを追加し、それらをUIViewControllerに接続して、Outlet Collectionを作成します。これらのビューは、カスタムビューインスタンスの "ラッパー"ビューとして機能します。 enter image description here

  5. 最後に、viewDidLoadUIViewControllerに以下の行を追加します。

NSArray *bundleObjects;
MyView *currView;
NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count];
for (UIView *currWrapperView in myWrapperViews) {
    bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    for (id object in bundleObjects) {
        if ([object isKindOfClass:[MyView class]]){
            currView = (MyView *)object;
            break;
        }
    }

    [currView.myLabel setText:@"myText"];
    [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal];
    //...

    [currWrapperView addSubview:currView];
    [myViews addObject:currView];
}
//self.myViews = myViews; if need to access them later..
22

私はUINibを使ってカスタムUIViewをインスタンス化して再利用する

UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];

この場合に必要なファイルは、MyCustomView.xibMyCustomViewClass.hおよびMyCustomViewClass.mです。[UINib instantiateWithOwner]は配列を返すので、次のようにしてください。再利用したいUIViewを反映する要素。この場合、それが最初の要素です。

18
thgc

Interface Builderでは、View ControllerのクラスをUIViewのサブクラスに設定しないでください。それは間違いなく少なくともあなたの問題の一部です。それをUIViewController、そのサブクラス、または他のカスタムクラスのいずれかとして残します。

Xibからのビューのみをロードすることに関しては、私はあなたが持っている何らかのビューコントローラを持っていると仮定していました(たとえUIViewControllerを拡張しなくても)。あなたがあなたのインタフェースを定義するためにそれを使用したい場合は、Interface Builderでファイルの所有者として設定します。私もこれを確認するために少し調査しました。これは、そうでなければUIView内のインターフェース要素にアクセスする方法がなく、またコード内の独自のメソッドをイベントによってトリガーする方法もないためです。

ビューのファイル所有者としてUIViewControllerを使用する場合は、initWithNibName:bundle:を使用してビューをロードし、View Controllerオブジェクトを元に戻すことができます。 IBでは、xibのインターフェースでviewアウトレットをビューに設定してください。 File's Ownerとして他の種類のオブジェクトを使用する場合は、NSBundleloadNibNamed:owner:options:メソッドを使用してnibをロードし、File's Ownerのインスタンスをそのメソッドに渡す必要があります。そのすべてのプロパティは、IBで定義したコンセントに従って正しく設定されます。

10
Marc W

LoadNibNamedの代わりにUIViewControllerのinitWithNibNameを使用することもできます。もっと簡単ですね。

UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release];  // release the VC

これで、MySubView.xibとMySubView.h/mを作成するだけです。 MySubView.xibで、File's OwnerクラスをUIViewControllerに、ビュークラスをMySubViewに設定します。

subviewの位置とサイズは、親のxibファイルを使用して指定できます。

10
Ying

これはもっと簡単なはずです。私はUIViewControllerを拡張してloadNib:inPlaceholder:セレクタを追加することになりました。今私は言うことができます

self.mySubview = (MyView *)[self loadNib:@"MyView" inPlaceholder:mySubview];

これがカテゴリのコードです(Gonsoが説明したのと同じrigamaroleを行います)。

@interface UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName;
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder;

@end

@implementation UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName
{
  NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; 
  for (id view in xib) { // have to iterate; index varies
    if ([view isKindOfClass:[UIView class]]) return view;
  }
  return nil;
}

- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
  UIView *nibView = [self viewFromNib:nibName];
  [nibView setFrame:placeholder.frame];
  [self.view insertSubview:nibView aboveSubview:placeholder];
  [placeholder removeFromSuperview];
  return nibView;
}

@end
8
skot

これは素晴らしい質問(+1)で、答えはほぼ参考になりました。)すみませんが、これに目をくぐることができました。うまくいけば、この答えは他の人を助けるでしょう。

MyVCは、これらすべてを保持するView Controllerです。

MySubviewは、xibからロードしたいビューです。

  • MyVC.xibで、正しいサイズ、形状、および希望の位置に配置されているタイプMySubViewのビューを作成します。
  • MyVC.hでは、

    IBOutlet MySubview *mySubView
    // ...
    @property (nonatomic, retain) MySubview *mySubview;
    
  • MyVC.mでは@synthesize mySubView;deallocでリリースすることを忘れないでください。

  • MySubview.hで、UIView *viewのアウトレット/プロパティを持っています(必要ではないかもしれませんが、私のために働きました)。
  • MySubview.xib に
    • ファイル所有者タイプをMySubviewに設定し、ビュープロパティを自分のビューにリンクします。
    • すべてのビットをレイアウトし、必要に応じてIBOutletに接続します。
  • MyVC.mに戻って、

    NSArray *xibviews = [[NSBundle mainBundle] loadNibNamed: @"MySubview" owner: mySubview options: NULL];
    MySubview *msView = [xibviews objectAtIndex: 0];
    msView.frame = mySubview.frame;
    UIView *oldView = mySubview;
    // Too simple: [self.view insertSubview: msView aboveSubview: mySubview];
    [[mySubview superview] insertSubview: msView aboveSubview: mySubview]; // allows nesting
    self.mySubview = msView;
    [oldCBView removeFromSuperview];
    

他の答えのヒントは私の見解をxibからロードしたが、MyVCの見解を置き換えなかった(当たり前) - 私は自分でそれを交換しなければならなかった。

また、mySubviewのメソッドにアクセスするには、.xibファイルのviewプロパティをMySubviewに設定する必要があります。それ以外の場合は、普通のUIViewとして返されます。

それ自身のxibから直接mySubviewをロードする方法があるなら、それはロックです、しかし、これは私がする必要があるところに私を得ました。

8
Olie

私も似たようなことをしたい、これが私が見つけたものです:(SDK 3.1.3)

ボタンを押すとVC BをロードするView Controller A(それ自体はNavコントローラが所有)を持っています。

AViewController.mに

BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];

VC BはBnibのインターフェースを持っていますが、ボタンが押されたときに別のペン先とは別のUIを持つ「編集モード」に入りたいのですが、新しいものは使いたくありません。 VC編集モードの場合、新しいペン先を既存のB VCに関連付ける必要があります。

だから、BViewController.mで(ボタンを押す方法で)

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"EditMode" owner:self options:nil];
UIView *theEditView = [nibObjects objectAtIndex:0];
self.editView = theEditView;
[self.view addSubview:theEditView];

次に別のボタンを押します(編集モードを終了するため)。

[editView removeFromSuperview];

そして元のBnibに戻ります。

これは問題なく動作しますが、私のEditMode.nibにはトップレベルオブジェクトが1つしかないことに注意してください(UIViewオブジェクト)。このペン先のファイルの所有者がBViewControllerとして設定されているか、デフォルトのNSObjectとして設定されているかは関係ありません。もしそうであれば、exc_bad_accessがクラッシュし、xcodeは6677スタックフレームをロードします。これは、内部UIViewメソッドが繰り返し呼び出されることを示しています...無限ループのように見えます。 (ビューアウトレットISただし、私のオリジナルのBnibに設定)

お役に立てれば。

6
Brynjar

Swiftでは

実際、この問題に対する私の解決策は、CustonViewControllerのviewDidLoadにビューをロードして、そのようなビューを使用することでした。

myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView

loadView()メソッドでビューをロードしないでください。 loadViewメソッドは、カスタムViewControllerのビューをロードするのに役立ちます。

6
kalafun

私は好きなカテゴリーを作りました:

UIView+NibInitializer.h

#import <UIKit/UIKit.h>

@interface UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil;
@end

UIView+NibInitializer.m

#import "UIView+NibInitializer.h"

@implementation UIView (NibInitializer)

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    if (!nibNameOrNil) {
        nibNameOrNil = NSStringFromClass([self class]);
    }
    NSArray *viewsInNib = [[NSBundle mainBundle] loadNibNamed:nibNameOrNil
                                                        owner:self
                                                      options:nil];
    for (id view in viewsInNib) {
        if ([view isKindOfClass:[self class]]) {
            self = view;
            break;
        }
    }
    return self;
}

@end

それから、次のように呼び出します。

MyCustomView *myCustomView = [[MyCustomView alloc] initWithNibNamed:nil];

あなたのペン先の名前があなたのクラスの名前以外のものである場合は、ペン先名を使用してください。

追加の動作のためにあなたのサブクラスでそれをオーバーライドするために、それはこのように見えるかもしれません:

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    self = [super initWithNibNamed:nibNameOrNil];
    if (self) {
        self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
    }
    return self;
}
6
Logan

設計可能なオプションを持つSwiftユーザーの場合:

  1. カスタムのUIViewサブクラスとxibファイルを作成します。これは、私たちの場合はMemeViewです。 Meme Viewクラス内では、クラス宣言の前に@IBDesignable属性で設計可能として定義することを忘れないでください。
  2. インデントインスペクタパネルのカスタムUIViewサブクラスを使用して、xibのファイルの所有者を設定することを忘れないでください

    enter image description here

  3. Xibファイルでは、インターフェイスの構築、制約の作成、アウトレットの作成、アクションなどができます。 enter image description here

  4. 初期化されたxibを開くためにカスタムクラスにいくつかのメソッドを実装する必要があります。

    class XibbedView: UIView {

    weak var nibView: UIView!
    
    override convenience init(frame: CGRect) {
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        self.init(nibName: nibName)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    init(nibName: String) {
        super.init(frame: CGRectZero)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    func setUpConstraints() {
        ["V","H"].forEach { (quote) -> () in
            let format = String(format:"\(quote):|[nibView]|")
            addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: ["nibView" : nibView]))
        }
    }
    
    func loadNib(name: String) -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: name, bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
    
        return view
    }
    

    }

  5. 私たちのカスタムクラスでは、インターフェイスビルダーからそれらを完全に制御するためにいくつかの不可解なプロパティを定義することもできます。

    @IBDesignable class MemeView: XibbedView {

    @IBInspectable var memeImage: UIImage = UIImage() {
        didSet {
            imageView.image = memeImage
        }
    }
    @IBInspectable var textColor: UIColor = UIColor.whiteColor() {
        didSet {
            label.textColor = textColor
        }
    }
    @IBInspectable var text: String = "" {
        didSet {
            label.text = text
        }
    }
    @IBInspectable var roundedCorners: Bool = false {
        didSet {
            if roundedCorners {
                layer.cornerRadius = 20.0
                clipsToBounds = true
            }
            else {
                layer.cornerRadius = 0.0
                clipsToBounds = false
            }
        }
    }
    
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var imageView: UIImageView!
    

}

いくつかの例:
enter image description hereenter image description here

prepareForInterfaceBuilder()を実装できるようにするために、ストーリーボードまたは別のxib内に表示されている間にビューにさらに情報を追加する必要がある場合、このメソッドはインターフェイスビルダーでファイルを開くときにのみ実行されます。私が書いたことをすべて行っても何も機能しない場合、それはその実装にブレークポイントを追加することによってシグレビューをデバッグする方法です。 enter image description here
これはビューの階層です。 View hiearchy

これがサンプル全体をダウンロードできることを願っています ここ

5
Andrea

Aaron Hillegass(作家、講師、Cocoa ninja)の このブログ投稿 は非常に啓発的なものです。指定されたイニシャライザを介してNIBファイルをロードするという彼の修正されたアプローチを採用しなくても、少なくとも進行中のプロセスについてよりよく理解するでしょう。私は最近この方法を使って大成功を収めました!

4
Meltemi

私は同じこと(XIBファイルからプログラム的にビューをロードすること)をする理由がありましたが、私はUIViewのサブクラスのサブクラスのコンテキストから(つまりビューコントローラを一切含まずに)完全にこれを行う必要がありました。これを行うために、私はこのユーティリティメソッドを作成しました:

+ (id) initWithNibName:(NSString *)nibName withSelf:(id)myself {

    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName
                                                    owner:myself options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:[myself class]]) {
            return object;
        }
    }  

    return nil;
} 

それから、サブクラスのinitWithFrameメソッドから次のように呼び出します。

- (id)initWithFrame:(CGRect)frame {

    self = [Utilities initWithNibName:@"XIB1" withSelf:self];
    if (self) {
        // Initialization code.
    }
    return self;
}

一般的な興味のために投稿されました。誰もがこの方法でそれをしないで何か問題を見た場合、私に知らせてください。

3
MusiGenesis

これはSwiftで行う方法です(現在XCode 7 Beta 5でSwift 2.0を書いています)。

Interface Builderで "Custom Class"として設定したUIViewサブクラスから、このようなメソッドを作成します(私のサブクラスはRecordingFooterViewと呼ばれます)。

class func loadFromNib() -> RecordingFooterView? {
    let nib = UINib(nibName: "RecordingFooterView", bundle: nil)
    let nibObjects = nib.instantiateWithOwner(nil, options: nil)
    if nibObjects.count > 0 {
        let topObject = nibObjects[0]
        return topObject as? RecordingFooterView
    }
    return nil
}

それならあなたはそれをこのように呼ぶことができます:

let recordingFooterView = RecordingFooterView.loadFromNib()

3
Johannes

前回の回答では、iPhone SDKの2.0から2.1の間に発生したNIB(XIB)構造の変更は考慮されていません。ユーザーコンテンツは、1ではなくインデックス0から始まります。

あなたはすべてのバージョン2.1以降に有効である2.1マクロを使うことができます(それはIPHONEの前に2つのアンダースコアです:

 // Cited from previous example
 NSArray* nibViews =  [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil];
 int startIndex;
 #ifdef __IPHONE_2_1
 startIndex = 0;
 #else
 startIndex = 1;
 #endif
 QPickOneView* myView = [ nibViews objectAtIndex: startIndex];
 myView.question = question;

私達は私達の適用のほとんどのためにこれと同じような技術を使用する。

バーニー

3
Barney Mattox

この質問の根底にあるスタンドアロンのXIBを作成する方法を説明する回答はありません。 "Create New XIB File"へのXcode 4オプションはありません。

これをする

1) Choose "New File..."
2) Choose the "User Interface" category under the iOS section
3) Choose the "View" item
4) You will then be prompted to choose an iPhone or iPad format

これは単純に思えるかもしれませんが、単語 "XIB"がどこにも現れないので、それを探し回ってあなたに数分を節約することができます。

2
whitneyland

@AVeryDev

6)ロードしたビューをView Controllerのビューに添付するには、次の手順に従います。

[self.view addSubview:myViewFromNib];

おそらく、メモリリークを防ぐためにビューから削除する必要があります。

明確にするために:View ControllerにはいくつかのIBOutletがあり、そのうちのいくつかは元のnibファイル内の項目に接続されており(一部は)、読み込まれたnib内の項目に接続されています。両方のペン先は同じ所有者クラスを持っています。ロードされたビューは元のビューをオーバーレイします。

ヒント:ロードしたペン先のメインビューの不透明度をゼロに設定すると、元のペン先のアイテムが見えにくくなりません。

1
Matt

最短バージョン:

RSFavoritePlaceholderView *favoritePlaceholderView = [[[NSBundle mainBundle] loadNibNamed:@"RSFavoritePlaceholderView" owner:self options:nil] firstObject];
1
wzbozon

何時間もかけて、私は次の解決策を考え出しました。カスタムUIViewを作成するには、次の手順に従います。

1)UIViewから継承したクラスmyCustomViewを作成します。
enter image description here

2)。xibを名前myCustomViewで作成します。
enter image description here

3).xibファイル内のUIViewのクラスを変更し、そこにmyCustomViewクラスを割り当てます。
enter image description here

4)IBOutletsを作成
enter image description here

5)myCustomView * customViewに.xibをロードします。次のサンプルコードを使用してください。

myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];

注:まだ問題に直面する人のためにコメントすることができ、私は彼らにmyCustomViewとサンプルプロジェクトのリンクを提供します

1
Aamir

ビューと同じように、ビューを持つxibに名前を付けるという規則があります。 View Controllerの場合と同じです。それから、クラス名をコードで書き出す必要はありません。私は同じ名前のnibファイルからUIViewをロードします。

MyViewというクラスの例。

  • Interface BuilderでMyView.xibという名前のnibファイルを作成します。
  • Interface Builderで、UIViewを追加します。そのクラスをMyViewに設定します。あなたの心のコンテンツに合わせてカスタマイズし、MyViewのインスタンス変数を後でアクセスしたいサブビューに結び付けます。
  • あなたのコードでは、このような新しいMyViewを作成してください:

    MyView * myView = [MyView nib_viewFromNibWithOwner:owner];

これがこのカテゴリです。

@implementation UIView (nib)

+ (id) nib_viewFromNib {
    return [self nib_viewFromNibWithOwner:nil];
}

+ (id) nib_viewFromNibWithOwner:(id)owner {
    NSString *className = NSStringFromClass([self class]);
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:className owner:owner options:nil];
    UIView *view = nil;
    for(UIView *v in nib) {
        if ([v isKindOfClass:[self class]]) {
            view = v;
            break;
        }
    }
    assert(view != nil && "View for class not found in nib file");
    [view nib_viewDidLoad];
    return view;
}

// override this to do custom setup
-(void)nib_viewDidLoad {

}

次に、私が使用しているコントローラからのアクションとボタンを関連付け、カスタムビューサブクラスのアウトレットを使用してラベルに物事を設定します。

0
n13

Swift 4でプログラム的にnib/xibからビューを読み込むには:

// Load a view from a Nib given a placeholder view subclass
//      Placeholder is an instance of the view to load.  Placeholder is discarded.
//      If no name is provided, the Nib name is the same as the subclass type name
//
public func loadViewFromNib<T>(placeholder placeholderView: T, name givenNibName: String? = nil) -> T {

    let nib = loadNib(givenNibName, placeholder: placeholderView)
    return instantiateView(fromNib: nib, placeholder: placeholderView)
}

// Step 1: Returns a Nib
//
public func loadNib<T>(_ givenNibName: String? = nil, placeholder placeholderView: T) -> UINib {
    //1. Load and unarchive nib file
    let nibName = givenNibName ?? String(describing: type(of: placeholderView))

    let nib = UINib(nibName: nibName, bundle: Bundle.main)
    return nib
}

// Step 2: Instantiate a view given a nib
//
public func instantiateView<T>(fromNib nib: UINib, placeholder placeholderView: T) -> T {
    //1. Get top level objects
    let topLevelObjects = nib.instantiate(withOwner: placeholderView, options: nil)

    //2. Have at least one top level object
    guard let firstObject = topLevelObjects.first else {
        fatalError("\(#function): no top level objects in nib")
    }

    //3. Return instantiated view, placeholderView is not used
    let instantiatedView = firstObject as! T
    return instantiatedView
}
0
Eng Yew