99

私はこの質問が以前に尋ねられたことを知っていますが、答えは矛盾していて混乱していますので、私を怒らせないでください。

アプリ全体で再利用可能なUIViewサブクラスが必要です。nibファイルを使用してインターフェースを説明したいと思います。

ここで、アクティビティインジケーターが含まれる読み込みインジケータービューであるとしましょう。あるイベントで、このビューをインスタンス化し、ビューコントローラのビューにアニメーション化したいと思います。プログラムで要素を作成し、initメソッド内にフレームを設定するなど、ビューのインターフェイスをプログラムで問題なく説明できます。

ペン先を使用してこれを行うにはどうすればよいですか?フレームを設定することなく、InterfaceBuilderで指定されたサイズを維持します。

私はなんとかこのようにそれを行うことができましたが、それは間違っていると確信しています(それはピッカーが入っている単なるビューです):

 - (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から取得するのではなく、手動で設定する必要があります。

編集:ビューコントローラでこのカスタムビューを作成し、ビューの要素を制御するためのアクセス権を持ちたいです。新しいViewControllerは必要ありません。

ありがとう

編集:これがベストプラクティスかどうかはわかりませんが、そうではないと確信していますが、これが私が行った方法です:

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) {
                        }];

正しい練習はまだ望んでいた

これは、ビューコントローラとペン先名の初期化を使用して実行する必要がありますか?コード内のUIView初期化メソッドでnibを設定する必要がありますか?それとも私がやったことは大丈夫ですか?

4

6 に答える 6

132
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必要がある場合があることを忘れないでください。(非常に価値のあるヒントは、テーブル セルの行に対してこれを行う場合は、絶対に行う必要があるということです。ビュー自体をコード内の関連するプロパティに接続する必要があります。)

于 2013-03-14T09:56:14.060 に答える
39

CustomViewと をからxib独立させたい場合はFile's Owner、次の手順に従います。

  • File's Ownerフィールドを空のままにします。
  • xibあなたのファイルの実際のビューをクリックして、それを(カスタムビュークラスの名前)としてCustomView設定しますCustom ClassCustomView
  • カスタム ビューのファイルに追加IBOutletします。.h
  • カスタム ビューのファイルで、.xib[ビュー] をクリックして に移動しConnection Inspectorます。.hここでは、ファイルで定義したすべての IBOutlets を使用します。
  • それらをそれぞれのビューに接続します。

クラスの.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場合は、次のコード行を使用します [[CustomView alloc] init];

于 2015-03-14T09:29:56.133 に答える
25

次の手順に従ってください

  1. type の MyView .h/.m という名前のクラスを作成しますUIView
  2. 同じ名前の xib を作成しますMyView.xib
  3. File Owner クラスをxib のUIViewControllerfromに変更します。NSObject下の画像を参照してください ここに画像の説明を入力
  4. ファイル所有者ビューをビューに接続します。下の画像を参照してください ここに画像の説明を入力

  5. ビューのクラスを に変更しますMyView。3と同じ。

  6. 配置コントロールは IBOutlets を作成します。

ビューをロードするコードは次のとおりです。

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

それが役に立てば幸い。

明確化:

UIViewControllerあなたのxibをロードするために使用され、UIViewController持っているビューは、実際MyViewにはMyView xibで割り当てたものです..

デモここで デモグラブを作成しました

于 2013-03-14T10:02:56.690 に答える
11

約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()
于 2016-01-08T09:28:18.923 に答える
8

スウィフトの場合:

たとえば、カスタム クラスの名前はInfoView

最初に、ファイルを作成し、次のInfoView.xibようInfoView.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 OwnerUIViewControllerます。

ここに画像の説明を入力

Viewあなたの名前をに変更しますInfoView

ここに画像の説明を入力

を右クリックして、フィールドを次のようFile's Ownerに接続します。viewInfoView

ここに画像の説明を入力

クラス名が であることを確認してくださいInfoView:

ここに画像の説明を入力

この後、問題なくカスタム クラスのボタンにアクションを追加できます。

ここに画像の説明を入力

そして、あなたのこのカスタムクラスの使用法MainViewController:

func someMethod() {
    var v = InfoView.instanceFromNib()
    v.frame = self.view.bounds
    self.view.addSubview(v)
}
于 2016-10-10T22:32:57.123 に答える
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 -- 管理します -- mainView
  • CustomView -- 必要に応じて xib からロードする必要があります。

以下のコードは、 view did load of 内に記述すると、後で混乱を招きますYourMainViewController。これはself.view、この時点からカスタムビューを参照するためです

-(void)viewDidLoad:(){
  UIView *childView= [[[NSBundle mainBundle] loadNibNamed:@"YourXibName" owner:self options:nil] objectAtIndex:0];
}
于 2013-03-14T10:50:59.760 に答える