programing

스토리보드에서 여러 컨트롤러와 함께 사용할 사용자 지정 셀을 만들려면 어떻게 해야 합니까?

powerit 2023. 5. 13. 11:02
반응형

스토리보드에서 여러 컨트롤러와 함께 사용할 사용자 지정 셀을 만들려면 어떻게 해야 합니까?

작업 중인 앱에서 스토리보드를 사용하려고 합니다.앱에는 Lists와 Users가 있으며 각각은 다른 그룹(List의 구성원, 사용자가 소유한 목록)의 컬렉션을 포함합니다.그래서, 그에 따라, 나는.ListCell그리고.UserCell 수업. 수업.목표는 애플리케이션 전체(즉, 내 모든 테이블 뷰 컨트롤러)에서 재사용할 수 있도록 하는 것입니다.

거기서 문제가 생깁니다.

모든 보기 컨트롤러에서 다시 사용할 수 있는 사용자 지정 테이블 보기 셀을 스토리보드에 만들려면 어떻게 해야 합니까?

여기 제가 지금까지 시도한 구체적인 것들이 있습니다.

  • 셀을 를 my 컨롤러 #1에서로프셀을클추래가다를니스설정합고로 했습니다.UITableViewCell하위 클래스에서 재사용 ID를 설정하고 레이블을 추가한 후 클래스의 콘센트에 연결합니다.컨트롤러 #2에서 빈 프로토타입 셀을 추가하여 이전과 동일한 클래스로 설정하고 재사용 ID를 사용합니다.실행 시 컨트롤러 #2에 셀이 표시될 때 라벨이 나타나지 않습니다.컨트롤러 #1에서 잘 작동합니다.

  • 다른 NIB에서 각 셀 유형을 설계하고 적절한 셀 클래스에 연결했습니다.스토리보드에서 빈 프로토타입 셀을 추가하고 클래스와 재사용 ID를 설정하여 내 셀 클래스를 참조합니다. controllers' 트롤에서러컨에viewDidLoad메서드, 재사용 ID에 대해 해당 NIB 파일을 등록했습니다.표시된 경우 두 컨트롤러의 셀은 프로토타입처럼 비어 있었습니다.

  • 두 컨트롤러의 프로토타입을 비워두고 클래스와 재사용 ID를 내 셀 클래스로 설정했습니다.셀의 UI를 완전히 코드로 구성했습니다.셀은 모든 컨트롤러에서 완벽하게 작동합니다.

두 번째 경우에는 프로토타입이 항상 NIB를 재정의하고 프로토타입 셀을 죽이면 재사용 ID에 대한 NIB를 등록할 수 있습니다.하지만 그러면 저는 셀에서 다른 프레임으로 segue를 설정할 수 없을 것입니다. 이것이 스토리보드를 사용하는 핵심입니다.

마지막으로, 저는 두 가지를 원합니다: 스토리보드의 테이블 뷰 기반 흐름을 연결하고 셀 레이아웃을 코드가 아닌 시각적으로 정의합니다.저는 지금까지 두 가지 모두를 어떻게 구할 수 있는지 모르겠습니다.

제가 이해하기로는, 당신은 다음을 원합니다.

  1. 여러 스토리보드 장면에서 사용할 수 있는 IB의 셀을 설계합니다.
  2. 셀이 있는 장면에 따라 해당 셀에서 고유한 스토리보드 세그먼트를 구성합니다.

안타깝게도 현재로서는 이 작업을 수행할 방법이 없습니다.이전 시도가 실패한 이유를 이해하려면 스토리보드와 프로토타입 테이블 뷰 셀이 작동하는 방식에 대해 자세히 이해해야 합니다.버그를 제출하는 것 외에는 마법적인 해결책이 없습니다.)

스토리보드는 본질적으로 .xib 파일 모음에 불과합니다.스토리보드에서 일부 프로토타입 셀이 있는 테이블 뷰 컨트롤러를 로드하면 다음과 같은 작업이 수행됩니다.

  • 각각의 프로토타입 셀은 실제로 내장된 미니 니브입니다.그래서 테이블 뷰 컨트롤러가 로드될 때 프로토타입 셀의 각 니브와 호출을 통해 실행됩니다.-[UITableView registerNib:forCellReuseIdentifier:].
  • 표 보기는 컨트롤러에 셀을 요청합니다.
  • 아마 전화하실 겁니다.-[UITableView dequeueReusableCellWithIdentifier:]
  • 지정된 재사용 식별자가 있는 셀을 요청하면 등록된 니브가 있는지 확인합니다.이 경우 해당 셀의 인스턴스를 인스턴스화합니다.이 작업은 다음 단계로 구성됩니다.

    1. 셀의 닙에 정의된 대로 셀의 클래스를 확인합니다.[[CellClass alloc] initWithCoder:].
    2. -initWithCoder:메서드는 nib에 정의된 하위 뷰와 속성을 차례로 추가하고 추가합니다.(IBOutlet그것을 아마 입니다; 제가그테하지않만지았스, 아도여연것입다니결될; 수다있일날습니어그것은도에기을것트마▁happen▁in▁s다있니▁as수습▁may▁it▁get;그▁probably▁that다일▁here것▁hooked▁up제어날▁though;은가,▁i'▁well▁tested.-awakeFromNib)
  • 원하는 대로 셀을 구성할 수 있습니다.

여기서 주목해야 할 중요한 것은 세포의 종류와 세포의 시각적 외관 사이에 차이가 있다는 것입니다.같은 클래스의 두 개의 개별 프로토타입 셀을 만들 수 있지만 하위 뷰는 완전히 다르게 배치됩니다.실제로 기본값을 사용하는 경우UITableViewCell스타일, 이게 바로 지금 일어나고 있는 일입니다.를 들어, "" 한 " 예들어부", "기본과" "제목일니" "은일게" "다하됩동표타스모시두일타스"로 됩니다.UITableViewCell학생들

이것은 중요합니다.셀의 클래스는 특정 보기 계층과 일대일 상관 관계가 없습니다.보기 계층 구조는 전적으로 이 특정 컨트롤러에 등록된 프로토타입 셀의 내용에 따라 결정됩니다.

또한 셀의 재사용 식별자가 일부 글로벌 셀 조제실에 등록되지 않았습니다. 재용식단컨에사서만다용니됩트텍의 내에서만 됩니다.UITableView사례.


이 정보를 바탕으로 위의 시도에서 어떤 일이 발생했는지 살펴보겠습니다.

컨트롤러 #1에서 프로토타입 셀을 추가하고 클래스를 내 UITableViewCell 하위 클래스로 설정하고 재사용 ID를 설정하고 레이블을 추가한 후 클래스의 콘센트에 연결합니다.컨트롤러 #2에서 빈 프로토타입 셀을 추가하여 이전과 동일한 클래스로 설정하고 재사용 ID를 사용합니다.실행 시 컨트롤러 #2에 셀이 표시될 때 라벨이 나타나지 않습니다.컨트롤러 #1에서 잘 작동합니다.

이것은 예상된 것입니다.두 셀 모두 클래스가 동일하지만 컨트롤러 #2의 셀로 전달된 보기 계층에는 하위 보기가 전혀 없습니다.그래서 여러분은 빈 세포를 얻었고, 이것이 바로 여러분이 프로토타입에 넣은 것입니다.

다른 NIB에서 각 셀 유형을 설계하고 적절한 셀 클래스에 연결했습니다.스토리보드에서 빈 프로토타입 셀을 추가하고 클래스와 재사용 ID를 설정하여 내 셀 클래스를 참조합니다.컨트롤러의 viewDidLoad 메서드에서 재사용 ID에 대해 해당 NIB 파일을 등록했습니다.표시된 경우 두 컨트롤러의 셀은 프로토타입처럼 비어 있었습니다.

다시 말하지만, 이것은 예상되는 것입니다.재사용 식별자는 스토리보드 씬(scene)이나 닙(nib) 간에 공유되지 않기 때문에 이러한 개별 셀이 모두 동일한 재사용 식별자를 가지고 있다는 사실은 의미가 없습니다.테이블 뷰에서 가져온 셀은 스토리보드의 해당 장면에 있는 프로토타입 셀과 일치하는 모양을 갖게 됩니다.

하지만 이 해결책은 근접했습니다.당신이 언급했듯이, 당신은 단지 프로그래밍 방식으로 전화를 걸 수 있습니다.-[UITableView registerNib:forCellReuseIdentifier:]京都를 UINib셀을 포함하면 동일한 셀을 다시 얻을 수 있습니다. (이것은 프로토타입이 닙을 "오버라이드"했기 때문이 아닙니다. 단순히 테이블 뷰에 닙을 등록하지 않았기 때문에 스토리보드에 내장된 닙을 보고 있었습니다.)불행히도 이 접근 방식에는 결함이 있습니다. 독립형 닙의 셀에 스토리보드 시게그를 연결할 방법이 없습니다.

두 컨트롤러의 프로토타입을 비워두고 클래스와 재사용 ID를 내 셀 클래스로 설정했습니다.셀의 UI를 완전히 코드로 구성했습니다.셀은 모든 컨트롤러에서 완벽하게 작동합니다.

당연히.이것이 놀랍지 않기를 바랍니다.


그래서 효과가 없었습니다.독립 실행형 닙에서 셀을 설계하고 여러 스토리보드 장면에서 사용할 수 있습니다. 현재는 해당 셀에 스토리보드 세그먼트를 연결할 수 없습니다.하지만, 여러분이 이 책을 읽는 과정에서 무언가를 배웠기를 바랍니다.

BJ Homer의 훌륭한 답변에도 불구하고 저는 해결책이 있다고 생각합니다.제 테스트에 관한 한, 효과가 있습니다.

개념: xib 셀에 대한 사용자 지정 클래스를 만듭니다.여기서 터치 이벤트를 기다렸다가 프로그래밍 방식으로 세그를 수행할 수 있습니다.이제 세그를 수행하는 컨트롤러에 대한 참조만 있으면 됩니다.내 해결책은 그것을 설정하는 것입니다.tableView:cellForRowAtIndexPath:.

나는 있습니다DetailedTaskCell.xib여러 테이블 보기에서 사용할 테이블 셀 포함:

Detailed TaskCell.xib

사용자 지정 클래스가 있습니다.TaskGuessTableCell해당 셀의 경우:

여기에 이미지 설명 입력

여기서 마법이 일어납니다.

// TaskGuessTableCell.h
#import <Foundation/Foundation.h>

@interface TaskGuessTableCell : UITableViewCell
@property (nonatomic, weak) UIViewController *controller;
@end

// TashGuessTableCell.m
#import "TaskGuessTableCell.h"

@implementation TaskGuessTableCell

@synthesize controller;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSIndexPath *path = [controller.tableView indexPathForCell:self];
    [controller.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    [controller performSegueWithIdentifier:@"FinishedTask" sender:controller];
    [super touchesEnded:touches withEvent:event];
}

@end

Segue가 여러 개 있지만 모두 이름이 같습니다."FinishedTask"여기서 융통성을 발휘해야 한다면, 저는 다른 부동산을 추가하는 것을 제안합니다.

View 컨트롤러의 모양은 다음과 같습니다.

// LogbookViewController.m
#import "LogbookViewController.h"
#import "TaskGuessTableCell.h"

@implementation LogbookViewController

- (void)viewDidLoad
{
    [super viewDidLoad]

    // register custom nib
    [self.tableView registerNib:[UINib nibWithNibName:@"DetailedTaskCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"DetailedTaskCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TaskGuessTableCell *cell;

    cell = [tableView dequeueReusableCellWithIdentifier:@"DetailedTaskCell"];
    cell.controller = self; // <-- the line that matters
    // if you added the seque property to the cell class, set that one here
    // cell.segue = @"TheSegueYouNeedToTrigger";
    cell.taskTitle.text  = [entry title];
    // set other outlet values etc. ...

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"FinishedTask"])
    {
        // do what you have to do, as usual
    }

}

@end

동일한 것을 달성하기 위한 더 우아한 방법이 있을 수 있지만 - 효과가 있습니다! :)

저는 이것을 찾다가 리처드 베너블의 답을 찾았습니다.저한테는 효과가 있어요.

iOS 5는 UITableView: registerNib: forCellRuseIdentifier:

이를 사용하려면 UITableViewCell을 닙에 넣습니다.닙의 유일한 루트 개체여야 합니다.

tableView를 로드한 후 decueReusableCellWithIdentifier를 호출하면 스토리보드 프로토타입 셀을 사용한 것처럼 nib에서 nib를 꺼냅니다.

BJ Homer는 무슨 일이 일어나고 있는지에 대한 훌륭한 설명을 해주었습니다.

실제적인 관점에서 보면 셀을 xib로 사용할 수 없고 segue를 연결할 수 없는 경우 가장 좋은 방법은 셀을 xib로 사용하는 것입니다. 여러 위치에서 셀 레이아웃과 속성을 전환하는 것보다 훨씬 쉽게 유지 관리할 수 있으며, 사용자의 segue는 다른 컨트롤러와 다를 수 있습니다.테이블 뷰 컨트롤러에서 다음 컨트롤러로 직접 segue를 정의하고 코드로 수행할 수 있습니다.

또한 셀을 별도의 xib 파일로 사용하면 작업 등을 테이블 보기 컨트롤러에 직접 연결할 수 없습니다(어쨌든 저는 이 문제를 해결하지 못했습니다. 파일의 소유자를 의미 있는 것으로 정의할 수 없습니다).셀의 테이블 뷰 컨트롤러가 준수할 것으로 예상되는 프로토콜을 정의하고 cellForRowAt에서 컨트롤러를 대리자와 유사한 취약한 속성으로 추가하여 이 문제를 해결하고 있습니다.인덱스 경로.

스위프트 3

BJ Homer가 설명을 잘 해줘서 개념을 이해하는데 도움이 됩니다..make a custom cell reusable in storyboard은 우리가 있는 모든 할 수 있습니다. TableView에서 사용할 수 있습니다.mix the Storyboard and xib접근.우리에게 다음과 같은 이름의 세포가 있다고 가정합니다.CustomCell은 에사서것용입다니에 입니다.TableViewControllerOne그리고.TableViewControllerTwo단계적으로 만들고 있습니다.
파일 > 새로 만들기 > 파일 클릭 > 코코아 터치 클래스 선택 > 다음 클릭 > 클래스 이름 지정(예:CustomCell> as > Next를 .) > UITableVieCell로 Subclass > 또한 XIB 파일을 생성합니다.
원하는 대로 셀을 사용자 정의하고 셀의 속성 검사기에서 식별자를 설정합니다. 여기서 다음과 같이 잘 설정됩니다.CellIdentifier이 식별자는 View 컨트롤러에서 셀을 식별하고 재사용하는 데 사용됩니다.
이제 우리는 해야만 합니다.register this cellviewDidLoad초기화 방법이 필요 없습니다.
이제 모든 테이블 보기에서 이 사용자 지정 셀을 사용할 수 있습니다.

테이블 뷰 컨트롤러 1에서

let reuseIdentifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell
    return cell!
}

저는 이러한 테스트가 아닌 동일한 VC에 대해 셀을 로드하는 방법을 찾았습니다.이것은 별도의 닙에 셀을 생성하기 위한 해결 방법일 수 있습니다.

VC 하나와 테이블 두 개가 있는데 스토리보드에서 셀을 설계하고 두 테이블 모두에서 사용하려고 합니다.

(예: 결과 테이블이 있는 UIS 검색 컨트롤러가 있는 테이블과 검색 필드, 두 개 모두에서 동일한 셀을 사용하려는 경우)

컨트롤러가 셀을 요청하면 다음을 수행합니다.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

그리고 여기 스토리보드에 있는 휴대폰이 있습니다.

제가 당신의 질문을 정확하게 이해한다면, 이것은 꽤 쉽습니다.성을 합니다.UIViewController스토리보드에서 프로토타입 셀을 고정하고 스토리보드에서 로드되는 정적 공유 인스턴스를 만들 수 있습니다. segue를 segue on delegate " 를 사용합니다.didSelectRow('First Responder'와 'Exit' 사이에 있는 스토리보드의 뷰 컨트롤러 상단에 있는 가운데 아이콘은 수동 segue 콘센트입니다.)

XCode 12.5, iOS 13.6

// A cell with a single UILabel

class UILabelCell: UITableViewCell {
    @IBOutlet weak var label: UILabel!
}

// A cell with a signle UISwitch

class UISwitchCell: UITableViewCell {
    @IBOutlet weak var uiSwitch: UISwitch!
}


// The TableViewController to hold the prototype cells.    

class CellPrototypeTableViewController: UITableViewController {
    
    // Loads the view controller from the storyboard
    
    static let shared: CellPrototypeTableViewController = {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "cellProtoypeVC") as! CellPrototypeTableViewController
        viewController.loadViewIfNeeded()  // Make sure to force view controller to load the view!
        return viewController
    }()

    
    // Helper methods to deque the cells
    
    func dequeUILabeCell() -> UILabelCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiLabelCell") as! UILabelCell
        return cell
    }
    
    func dequeUISwitchCell() -> UISwitchCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiSwitchCell") as! UISwitchCell
        return cell
    }
}

사용:

class MyTableViewController: UITableViewController {
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // Dequeue the cells from the shared instance
        
        switch indexPath.row {
        case 0:
            let uiLabelCell = CellPrototypeTableViewController.shared.dequeUILabeCell()
            uiLabelCell.label.text = "Hello World"
            return uiLabelCell
        case 1:
            let uiSwitchCell = CellPrototypeTableViewController.shared.dequeUISwitchCell()
            uiSwitchCell.uiSwitch.isOn = false
            return uiSwitchCell
        default:
            fatalError("IndexPath out of bounds")
        }
    }
    
    // Handling Segues
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.row {
        case 0: self.performSegue(withIdentifier: "first", sender: nil)
        case 1: self.performSegue(withIdentifier: "second", sender: nil)
        default:
            fatalError("IndexPath out of bounds")
        }
    }
}

언급URL : https://stackoverflow.com/questions/9245969/in-a-storyboard-how-do-i-make-a-custom-cell-for-use-with-multiple-controllers

반응형