테이블 뷰를 사용할 때마다 가장 손이 많이 가는 부분이 UITableViewCell이다.
이 cell을 대부분 상속을 받아 커스텀으로 사용을 하게 되는데 커스텀의 모양이 생각대로 안나오기 때문이다.

몇 차례 삽질을 한 결과 몇 가지 결론을 얻었다.

우선 cell의 subview는 몇가지 나눠져 있다.

cell.imageView
cell.text
cell.contentView
cell.accessoryView

등으로 구성되어져 있다.

우선 ios5가되면서 imageView와 text 뷰는 deprecate 체크가 되어있어 사용하면 안될 것이다. 그럼 위 imageView와 text뷰를 대체할 서브뷰를 생성하기 위해서 커스텀 뷰내에 UIImageView 객체와 UILabel 객체를 추가하였다.

하지만 여기서 가장 큰 걸림돌이 초기화 할때 위치와 layoutSubviews가 호출될 때하고 cell의 값이 너무 달라져 버려 어느 위치에 서브뷰들을 위치 시켜야 할지 혼란에 빠졌다. 여기에서 몇가지 규칙을 찾아냈다.

1. 초기화될때 cell의 높이는 정해져 있다.

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier

위와 같이 초기화를 시켜줄때 쎌의 높이 넓이 값은 따로 지정하지 않아도 그 값이 정해져 있다. (심지어 tableView의 delegate를 통해 설정된 값 역시 반영되지 않는다. self.bounds의 값을 찍어보면 알수 있을 것이다.)

그러므로 초기화 할때는 각 서브뷰들의 객체 할당만 시켜주면 될것이다.

높이, 넓이 값 뿐만 아니라 다른 값들 역시 쎌의 속성에 제대로 반영되지 않는다. 배경색 이나 기타 cell에 관련된 값이 제대로 반영되지 않는다.
(확실 하지 않지만 subview들의 속성들도 일부 변경된다. opaque 상태등등...)

결론은 초기화 할때 많은 것을 지정할 필요가 없다. 단순히 객체만 생성해주면 된다.

2. 실제 위치는 layoutSubviews에서 결정된다.

위 메소드에서 실제 위치가 결정되는데 보통 일반 뷰에서는 [super layoutSubviews]를 잘 실행하지 않는 경우가 종종있다. 하지만 cell 에서는 위 메소드를 실행 유무에 따라 그 결과 값이 달라진다.

우선 위 메소드를 실행하지 않게 되면 cell의 기본적인 subview들이 제대로 위치를 잡지 못한다. 즉 contentView나 accessoryView, 심지어 cell의 line 역시 제대로 그려지지 않게 된다. 즉 cell의 완전히 커스텀해서 사용하고 싶을때는 상위 클래스의 layoutSubviews를 실행하지 않는다.

하지만 기본적으로 제공하는 accessoryView나 cell의 line을 사용하면 편한 경우가 종종 있다. 이럴 경우 상위 클래스의 layoutSubviews를 꼭 실행해야한다. 하지만 이 메소드를 실행하다고해서 뷰를 마음대로 컨트롤하기는 거의 불가능 하다 (정신건강에도 이롭다.) 왜냐면 사용자에게 노출되지 않은 부분에서 위치 및 높이 넓이 값이 재정의 되기 때문에 아무리 오버라이드를 해도 변경하기 힘들다.

그리고 layoutSubviews가 실행될때에는  tableView에서 설정한 높이 값이 제대로 전달되어 들어온다. 이 높이 넓이 값을 이용하여 초기화에서 만든 서브뷰들의 위치를 재정의 하여 원하는 위치에 뷰를 옮긴다. 여기서 주의해야 할 점은 contentView인데 이 contentView 역시 위 메소드를 실행하면 값이 재정의되어 있는 상태이다. (안쓰이게되는 imageView와 text 값 등에 의해 위치가 변경된듯 하다)

이 재정의된 위치 값은 어차피 imageView 와 text는 안쓰이게 되므로 위치를 변경한다.

또한 배경값이나 기타 쎌에 괄련된 속성 역시 여기서 지정해 준다. (tableView의 reusequeue를 거치면서 초기화때 cell에 지정한 속성 값들이 재정의되어버린듯 하다. 하지만 subview의 속성은 일부 유지된다.)

기본적인 이미지, 텍스트 cell예제


- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier

{

    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];

    

    if (self) {
        // 서브뷰를 정의한다. 

        UIImageView * iconView = [[UIImageView alloc]init ];

        [self.contentView addSubview:iconView];

        i_FolderIcon = iconView;

        [iconView release];

        

        UILabel * folderName = [[UILabel alloc]init];

        [self.contentView addSubview:folderName];

        i_FolderName = folderName;

        [folderName release];

    }

    return self;

}


- (void) dealloc {

    self.cellColor = nil;

    [super dealloc];

}


- (void) layoutSubviews {

     // 쎌의 위치 및 속성등을 재정의한다.

    [super layoutSubviews];

    

    self.backgroundColor = self.cellColor;

    self.contentView.frame = self.bounds;

    

    CGRect frame = self.bounds;

    CGRect iconFrame = CGRectMake(0, 0, frame.size.height, frame.size.height);

    i_FolderIcon.frame = iconFrame;

    i_FolderIcon.opaque = YES;

    

    CGRect folderNameFrame = CGRectZero;

    folderNameFrame.origin = CGPointMake(iconFrame.size.width+5, 0);

    folderNameFrame.size = CGSizeMake(frame.size.width - (iconFrame.size.width+5), frame.size.height);

    i_FolderName.frame = folderNameFrame;

    i_FolderName.opaque = YES;

}


- (void) setFolderIcon:(UIImage *) iconImage {

    

    i_FolderIcon.image = iconImage;

    

}


- (void) setFolderName:(NSString *) folderName {

    

    NSString * name = [[NSString alloc]initWithString:folderName];

    i_FolderName.text = name;

    [name release];

}








 

+ Recent posts