私はこの質問が以前に尋ねられたことを知っていますが、答えは矛盾しており、私は混乱しています。
アプリ全体で再利用可能なUIView
サブクラスが必要です。 nibファイルを使用してインターフェイスを説明します。
ここで、アクティビティインジケータを含むローディングインジケータビューであるとします。何らかのイベントでこのビューをインスタンス化し、View Controllerのビューにアニメーション化したいと思います。ビューのインターフェースをプログラムで問題なく記述し、要素をプログラムで作成し、フレームを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から取得するのではなく、手動で設定する必要があります。
編集:ビューコントローラーでこのカスタムビューを作成し、ビューの要素を制御するアクセス権があります。新しいView Controllerは必要ありません。
ありがとう
編集:これがベストプラクティスであるかどうかはわかりませんが、そうではないはずですが、これが私がやった方法です:
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) {
}];
正しい練習がまだ必要
これは、View Controllerとinitをnib名で使用して行う必要がありますか?コード内のいくつかのUIView初期化メソッドでペン先を設定する必要がありますか?それとも私がやったことは大丈夫ですか?
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
では、ビュー自体をクリックし、必要に応じてアウトレットにドラッグする必要がある場合があることを忘れないでください。 (非常に価値のあるヒントは、テーブルセル行に対してこれを行う場合、絶対に行う必要があるということです。ビュー自体をコード内の関連するプロパティに接続する必要があります。)
CustomView
とそのxib
をFile's Owner
から独立させたい場合は、次の手順に従ってください
File's Owner
フィールドは空のままにします。xib
のCustomView
ファイルで実際のビューをクリックし、そのCustom Class
をCustomView
(カスタムビュークラスの名前)として設定します.h
ファイルにIBOutlet
を追加します。.xib
ファイルで、ビューをクリックしてConnection Inspector
に進みます。ここでは、.h
ファイルで定義するすべてのIBOutletsを作成しますCustomView
クラスの.m
ファイルで、次のように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];
を使用します
次の手順に従ってください
UIView
のMyView .h/.mという名前のクラスを作成します。MyView.xib
のxibを作成します。UIViewController
からNSObject
に変更します。下の画像をご覧ください ファイル所有者ビューをビューに接続します。下の画像をご覧ください
ビューのクラスをMyView
に変更します。 3と同じ。
ビューをロードするコードは次のとおりです。
UIViewController *controller=[[UIViewController alloc] initWithNibName:@"MyView" bundle:nil];
MyView* view=(MyView*)controller.view;
[self.view addSubview:myview];
それが役に立てば幸い。
明確化:
UIViewController
はxibをロードするために使用され、UIViewController
が持つビューは、実際にはMyView
で、MyView xibで割り当てています。
Demoデモを取得しました here
ここで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()
Swiftの場合:
たとえば、カスタムクラスの名前は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 Owner
をUIViewController
に次のように設定します。
View
の名前をInfoView
に変更します。
File's Owner
を右クリックして、view
フィールドをInfoView
に接続します。
クラス名がInfoView
であることを確認してください:
この後、カスタムクラスのボタンに問題なくアクションを追加できます。
MainViewController
でのこのカスタムクラスの使用法:
func someMethod() {
var v = InfoView.instanceFromNib()
v.frame = self.view.bounds
self.view.addSubview(v)
}
さて、View Controllerを使用して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を設定し、ビュープロパティを新しいxibビューに関連付けた場合、この問題に直面します。
すなわち
以下のコードは、YourMainViewController
のロードを行ったビュー内で記述した場合、後で混乱を引き起こします。これは、この時点からself.view
がカスタムビューを参照するためです
-(void)viewDidLoad:(){
UIView *childView= [[[NSBundle mainBundle] loadNibNamed:@"YourXibName" owner:self options:nil] objectAtIndex:0];
}