programing

사용자 지정 iOS 보기 클래스를 만들고 여러 복사본(IB)을 인스턴스화하려면 어떻게 해야 합니까?

stoneblock 2023. 5. 29. 09:16

사용자 지정 iOS 보기 클래스를 만들고 여러 복사본(IB)을 인스턴스화하려면 어떻게 해야 합니까?

저는 현재 여러 개의 타이머가 있는 앱을 만들고 있는데, 기본적으로 모두 동일합니다.

타이머뿐만 아니라 레이아웃/애니메이션에 대한 모든 코드를 사용하는 사용자 지정 클래스를 만들어 서로 독립적으로 작동하는 동일한 타이머 5개를 만들 수 있습니다.

IB(xcode 4.2)를 사용하여 레이아웃을 생성했으며 타이머의 모든 코드는 현재 View controller 클래스에 있습니다.

모든 것을 사용자 지정 클래스로 캡슐화한 다음 뷰 컨트롤러에 추가하는 방법에 대해 머리를 싸매는 데 어려움이 있습니다. 어떤 도움이든 감사하겠습니다.

신속한 예

Xcode 10 및 Swift 4용으로 업데이트됨(보고에 따르면 Xcode 12.4/Swift 5용으로 계속 작동함)

여기에 기본적인 설명이 있습니다.저는 원래 이 유튜브 영상 시리즈를 보고 많은 것을 배웠습니다.나중에 저는 이 기사를 바탕으로 답변을 업데이트했습니다.

사용자 정의 보기 파일 추가

다음 두 개의 파일이 사용자 정의 보기를 형성합니다.

  • 레이아웃을 포함하는 .xib 파일
  • .을 .로 표시합니다파일을 다음과 같이 지정UIView

추가에 대한 자세한 내용은 아래와 같습니다.

Xib 파일

프로젝트에 .xib 파일을 추가합니다(파일 > 새로 만들기 > 파일... > 사용자 인터페이스 > 보기).나는 내 것을 부릅니다.ReusableCustomView.xib.

사용자 정의 보기에 사용할 레이아웃을 만듭니다.예를 들어, 저는 다음과 같이 레이아웃을 만들 것입니다.UILabel a 리고a.UIButton나중에 어떤 크기로 설정하든 자동으로 크기가 조정되도록 자동 레이아웃을 사용하는 것이 좋습니다. (Attributes inspector(속성 검사기)에서 xib 크기에 대해 Freeform(자유형)을 사용하여 시뮬레이션 메트릭을 조정했지만 그럴 필요는 없습니다.)

여기에 이미지 설명 입력

스위프트 파일

프로젝트에 .swift 파일을 추가합니다(파일 > 새로 만들기 > 파일... > 출처 > 스위프트 파일).의 하위 클래스입니다.UIView그리고 나는 내 것을 부를 것입니다.ReusableCustomView.swift.

import UIKit
class ResuableCustomView: UIView {

}

Swift 파일을 소유자로 지정

.xib 파일로 돌아가서 문서 개요에서 "파일 소유자"를 클릭합니다.Identity Inspector에 .swift 파일의 이름을 사용자 지정 클래스 이름으로 입력합니다.

여기에 이미지 설명 입력

사용자 지정 보기 코드 추가

를 합니다.ReusableCustomView.swift파일의 내용을 다음 코드로 표시합니다.

import UIKit

@IBDesignable
class ResuableCustomView: UIView {
    
    let nibName = "ReusableCustomView"
    var contentView:UIView?
    
    @IBOutlet weak var label: UILabel!
    
    @IBAction func buttonTap(_ sender: UIButton) {
        label.text = "Hi"
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    func commonInit() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
    }
    
    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
}

.xib 파일의 이름에 맞는 철자를 입력해야 합니다.

콘센트 연결 및 조치

xib 레이아웃의 레이블과 버튼에서 신속한 사용자 정의 보기 코드로 끌어서 배출구와 동작을 연결합니다.

사용자 정의 보기 사용

이제 사용자 정의 보기가 완료되었습니다.▁a다를 만 하면 됩니다.UIView메인 스토리보드에서 원하는 위치로 이동할 수 있습니다.보기의 클래스 이름을 다음으로 설정합니다.ReusableCustomView신원 조사관에게 말입니다.

여기에 이미지 설명 입력

, 는 아마 개적으대답면자, 하의타아다마음도하의위것클다입의 입니다.UIViewNSObject.

.UIView보기 컨트롤러 보기에서 삭제하고 타이머의 클래스 이름으로 클래스를 설정합니다.

여기에 이미지 설명 입력

말고 기억하세요#import타이머 클래스가 표시됩니다.

편집: IB 설계의 경우(코드 인스턴스화는 수정 내역 참조)

스토리보드에 , 당신이 에서 당신의 할 수 은 알고 있습니다..xib버전을 ; 수 ..xibjava.

이를 테스트하기 위해 빈 공간을 새로 만들었습니다..xib파일 "MyCustomTimerView.xib"입니다.그리고 나서 저는 뷰를 추가했고, 거기에 레이블과 두 개의 버튼을 추가했습니다.를 들어 So 아요소좋:

여기에 이미지 설명 입력

클래스 .UIView"My Custom Timer"는 "My Custom Timer"입니다.내 안에서.xibFile's Owner 클래스를 MyCustomTimer로 설정했습니다.이제 다른 보기/컨트롤러와 마찬가지로 작업과 아웃렛을 자유롭게 연결할 수 있습니다.그 결과.h파일은 다음과 같습니다.

@interface MyCustomTimer : UIView
@property (strong, nonatomic) IBOutlet UILabel *displayLabel;
@property (strong, nonatomic) IBOutlet UIButton *startButton;
@property (strong, nonatomic) IBOutlet UIButton *stopButton;
- (IBAction)startButtonPush:(id)sender;
- (IBAction)stopButtonPush:(id)sender;
@end

점프할 수 있는 유일한 장애물은 이것을 얻는 것입니다..xib 돈으로UIView아류의사용.xib필요한 설정을 대폭 줄입니다.그리고 스토리보드를 사용하여 타이머를 로드하고 있기 때문에-(id)initWithCoder:이 호출되는 유일한 이니셜라이저입니다.구현 파일은 다음과 같습니다.

#import "MyCustomTimer.h"
@implementation MyCustomTimer
@synthesize displayLabel;
@synthesize startButton;
@synthesize stopButton;
-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super initWithCoder:aDecoder])){
        [self addSubview:
         [[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" 
                                        owner:self 
                                      options:nil] objectAtIndex:0]];
    }
    return self;
}
- (IBAction)startButtonPush:(id)sender {
    self.displayLabel.backgroundColor = [UIColor greenColor];
}
- (IBAction)stopButtonPush:(id)sender {
    self.displayLabel.backgroundColor = [UIColor redColor];
}
@end

이름의 loadNibNamed:owner:options:정확하게 들리는 대로 행동합니다.Nib를 로드하고 "파일 소유자" 속성을 자체로 설정합니다.배열의 첫 번째 객체를 추출합니다. 이것이 니브의 루트 뷰입니다.뷰를 하위 뷰로 추가하고 Voila가 화면에 표시됩니다.

분명히 이것은 버튼을 누를 때 레이블의 배경색을 변경할 뿐이지만, 이 예제를 사용하면 사용자가 순조롭게 진행할 수 있습니다.

주석 기반 참고 사항:

무한 재귀 문제가 발생하는 경우 이 솔루션의 미묘한 트릭을 놓쳤을 수 있습니다.그것은 당신이 생각하는 것과 다릅니다.스토리보드에 배치된 보기는 표시되지 않고 다른 보기를 하위 보기로 로드합니다.로드되는 뷰는 니브에 정의된 뷰입니다.닙의 "파일 소유자"는 보이지 않는 보기입니다.멋진 부분은 이 보이지 않는 뷰가 여전히 Objective-C 클래스이며, 닙에서 가져온 뷰에 대한 일종의 뷰 컨트롤러로 사용될 수 있다는 것입니다.를 들어, 를들어예,,IBActionMyCustomTimer클래스는 보기보다 보기 컨트롤러에서 더 많은 것을 기대할 수 있습니다.

참고로, 일부 사람들은 이것이 깨졌다고 주장할 수 있습니다.MVC어느 정도 동의합니다.제 관점에서는 그것은 관습과 더 밀접한 관련이 있습니다.UITableViewCell부품 관리자도 필요한 경우도 있습니다.

또한 이 답변은 매우 구체적인 솔루션을 제공하기 위한 것이었다는 점에 주목할 필요가 있습니다. 스토리보드에 배치된 것과 동일한 뷰에서 여러 번 인스턴스화할 수 있는 하나의 닙을 생성할 수 있습니다.예를 들어, 여러분은 아이패드 화면에서 한 번에 여섯 개의 타이머를 쉽게 상상할 수 있습니다.애플리케이션 전체에서 여러 번 사용할 뷰 컨트롤러에 대한 뷰만 지정하면 된다면 jyavard에서 제공하는 솔루션이 이 질문에 대한 더 나은 솔루션임이 거의 확실합니다.

뷰가 아닌 뷰 컨트롤러에 대한 답변:

스토리보드에서 xib를 로드하는 더 쉬운 방법이 있습니다.가 MyClassController에서 합니다.UIViewController.

추가합니다.UIViewController스토리보드에서 IB를 사용하여 클래스 유형을 MyClassController로 변경합니다.스토리보드에 자동으로 추가된 보기를 삭제합니다.

호출할 XIB가 MyClassController.xib인지 확인합니다.

스토리보드 로드 중에 클래스가 인스턴스화되면 xib가 자동으로 로드됩니다.그 이유는 기본 구현 때문입니다.UIViewController클래스 이름으로 명명된 XIB를 호출합니다.

이것은 실제로 답은 아니지만, 저는 이 접근법을 공유하는 것이 도움이 된다고 생각합니다.

목표-C

  1. 사용자 정의 보기 가져오기Xib.h사용자 지정 보기 사용프로젝트에 대한 Xib.m 사용
  2. 동일한 이름(.h / .m / .xib)으로 사용자 정의 보기 파일 생성
  3. CustomView에서 사용자 정의 클래스 상속Xib 포함

스위프트

  1. 사용자 정의 보기 가져오기Xib.swift를 사용하여 프로젝트 진행
  2. 동일한 이름(.swift 및 .xib)을 사용하여 사용자 정의 보기 파일
  3. CustomView에서 사용자 정의 클래스 상속Xib 포함

선택 사항:

  1. xib 파일로 이동하여 일부 요소를 연결해야 할 경우 사용자 지정 클래스 이름으로 소유자를 설정합니다(자세한 내용은 스위프트 파일을 @Suragch answer의 소유자로 만들기 부분 참조).

이제 사용자 정의 보기를 스토리보드에 추가할 수 있습니다. 그러면 표시됩니다.

사용자 정의 보기Xib.h 포함:

 #import <UIKit/UIKit.h>

/**
 *  All classes inherit from CustomViewWithXib should have the same xib file name and class name (.h and .m)
 MyCustomView.h
 MyCustomView.m
 MyCustomView.xib
 */

// This allows seeing how your custom views will appear without building and running your app after each change.
IB_DESIGNABLE
@interface CustomViewWithXib : UIView

@end

사용자 정의 보기Xib.m 포함:

#import "CustomViewWithXib.h"

@implementation CustomViewWithXib

#pragma mark - init methods

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // load view frame XIB
        [self commonSetup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // load view frame XIB
        [self commonSetup];
    }
    return self;
}

#pragma mark - setup view

- (UIView *)loadViewFromNib {
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];

    //  An exception will be thrown if the xib file with this class name not found,
    UIView *view = [[bundle loadNibNamed:NSStringFromClass([self class])  owner:self options:nil] firstObject];
    return view;
}

- (void)commonSetup {
    UIView *nibView = [self loadViewFromNib];
    nibView.frame = self.bounds;
    // the autoresizingMask will be converted to constraints, the frame will match the parent view frame
    nibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    // Adding nibView on the top of our view
    [self addSubview:nibView];
}

@end

사용자 정의 보기Xib.swift 사용 시:

import UIKit

@IBDesignable
class CustomViewWithXib: UIView {

    // MARK: init methods
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        commonSetup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        commonSetup()
    }

    // MARK: setup view 

    private func loadViewFromNib() -> UIView {
        let viewBundle = NSBundle(forClass: self.dynamicType)
        //  An exception will be thrown if the xib file with this class name not found,
        let view = viewBundle.loadNibNamed(String(self.dynamicType), owner: self, options: nil)[0]
        return view as! UIView
    }

    private func commonSetup() {
        let nibView = loadViewFromNib()
        nibView.frame = bounds
        // the autoresizingMask will be converted to constraints, the frame will match the parent view frame
        nibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        // Adding nibView on the top of our view
        addSubview(nibView)
    }
}

여기에서 몇 가지 를 찾을 수 있습니다.

도움이 되길 바랍니다.

언급URL : https://stackoverflow.com/questions/9251202/how-do-i-create-a-custom-ios-view-class-and-instantiate-multiple-copies-of-it-i