[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];


답변

다음 단계를 따르십시오.

  1. MyView .h / .m 유형의 클래스를 만듭니다 UIView.
  2. 같은 이름의 xib를 만듭니다 MyView.xib.
  3. 이제 xib UIViewController에서 파일 소유자 클래스를 from NSObject으로 변경하십시오 . 아래 이미지를 참조하십시오
    여기에 이미지 설명 입력
  4. 파일 소유자보기를보기에 연결합니다. 아래 이미지를 참조하십시오
    여기에 이미지 설명 입력

  5. 보기 클래스를 다음으로 변경하십시오. MyView . 3과 같습니다.

  6. 장소 컨트롤은 IBOutlets를 만듭니다.

보기를로드하는 코드는 다음과 같습니다.

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

도움이되기를 바랍니다.

설명 :

UIViewControllerxib를로드하는 데 사용되며 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.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이 좋아 :

여기에 이미지 설명 입력

당신의 이름 바꾸기 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];
}


답변