[iphone] UIView 하위 클래스에 대한 Nib을로드하는 올바른 방법
이 질문이 이전에 요청 된 것을 알고 있지만 답변이 모순되고 혼란 스럽기 때문에 나를 화나게하지 마십시오.
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;
}
그러나 나는 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 이름으로 초기화해야합니까? 코드의 일부 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
(사용자 정의 뷰 클래스의 이름) - 추가
IBOutlet
의.h
사용자 정의보기 파일. - 에서
.xib
사용자 정의보기의 파일보기를 클릭하고 들어가Connection Inspector
. 여기에.h
파일에 정의한 모든 IBOutlets가 있습니다. - 그들 각각의 관점으로 그들을 연결하십시오.
에 .m
당신의 파일 CustomView
클래스의 오버라이드 (override) 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];
답변
다음 단계를 따르십시오.
- MyView .h / .m 유형의 클래스를 만듭니다
UIView
. - 같은 이름의 xib를 만듭니다
MyView.xib
. - 이제 xib
UIViewController
에서 파일 소유자 클래스를 fromNSObject
으로 변경하십시오 . 아래 이미지를 참조하십시오
-
파일 소유자보기를보기에 연결합니다. 아래 이미지를 참조하십시오
-
보기 클래스를 다음으로 변경하십시오.
MyView
. 3과 같습니다. - 장소 컨트롤은 IBOutlets를 만듭니다.
보기를로드하는 코드는 다음과 같습니다.
UIViewController *controller=[[UIViewController alloc] initWithNibName:@"MyView" bundle:nil];
MyView* view=(MyView*)controller.view;
[self.view addSubview:myview];
도움이되기를 바랍니다.
설명 :
UIViewController
xib를로드하는 데 사용되며 UIViewController
실제로 MyView
있는 뷰 는 MyView xib에서 할당 한 것입니다.
데모 여기서
데모를 만들었습니다.
답변
여기에서 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)
}
답변
보기 컨트롤러를 사용하여 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-관리-mainView
- CustomView-필요할 때 xib에서로드해야합니다.
아래 코드는 내부 뷰를 작성하면 나중에 혼란을 일으킬 것입니다 YourMainViewController
. 그 때문입니다 self.view
당신의있는 CustomView를 참조 할이 시점에서
-(void)viewDidLoad:(){
UIView *childView= [[[NSBundle mainBundle] loadNibNamed:@"YourXibName" owner:self options:nil] objectAtIndex:0];
}