Things take time

[SWIFT] 테이블 뷰 에서 AutomaticDimension 사용시, 이미지뷰에 따른 높이 조절하기 본문

iOS (기능)

[SWIFT] 테이블 뷰 에서 AutomaticDimension 사용시, 이미지뷰에 따른 높이 조절하기

겸손할 겸 2019. 4. 8. 15:27

[개요]

 

테이블 뷰를 사용하다보면, 각 테이블의 높이를 두 종류로 사용한다.

 

1. 직접 테이블 뷰의 높이를 지정한다. 이런 경우, 테이블 뷰에 그릴 UI나 높이가 고정 값일때, 즉 Static Cell처럼 사용할 때 주로 쓴다.

2. 테이블 뷰의 높이를 automaticDimension으로 설정하여 heightForRowAt이란 함수를 오버라이드 하지 않는다. 이 함수는 들어가는 콘텐츠 크기에 따라 알아서 잡아준다.

 

현재 하고 있는 작업은 1번으로 작성된 동적인 뷰를 2번으로 바꾸고 있다. 왜 1번으로 했는지는 아직도 의문(?)

점점 사용할 템플릿 Cell이 많아지기 때문에 1번을 사용할 경우 cellForRowAt에서도 동적으로 써야하고, heightForRowAt에서도 cellForRowAt에서 사용한 코드를 가져다가 다시 sizeToFit()해서 계산하는 등.. 비효율의 끝이다.

템플릿이 초반에 비해 많이 증가해서 작업 소요시간이 너무 오래 걸리는 단점이 있지만, 소스 코드를 줄이고 유지 보수를 위해 2번으로!

 

어쨌든, 2번을 사용하기 위한 가장 기초적인 필수 조건

 

TableView안에 들어가는 TableViewCell은 Constraint가 삐딱하지 않게 다 맞아야하며, 특히 위 아래의 Constraint가 제대로 설정 되어야한다.

 

안에 들어가는 텍스트 라벨에 따라 달라질 Cell

예를 들어 이런 셀을 만들었다고 보자.

여기서 위에 말한 필수 조건은, 이미지 뷰와 이름 라벨은 상단부터 어느정도 위치에 있는지 정해야한다. 그리고 하단과 붙어있는 저 파란색 뷰는 높이, Height를 지정하는것이 아니라 바닥부터 어느정도 위치에 있는지 정해야한다.

 

동적인 뷰라고하면, 저 파란색 박스안에 들어갈 Label값이 길어지거나 짧아질 수 있기 때문에 Height를 직접 지정하지 않는다. 그러므로 저 안에 있는 Label을 sizeToFit()을 하게 되면, 알아서 Label의 개수에 따라 파란색 뷰가 커지거나 짧아지는 것이다. (당연하지만, Label도 파란색 뷰 안에 채워지도록 제약조건이 걸려 있어야 한다.)

 

제약조건만 잘 채우면 AutomaticDimension이 잘 된다는 뜻이다.

 

[문제]

 

이미지 뷰가 들어간 Cell

위의 경우에 맞춰서 이미지 뷰도 이렇게 맞춰놓았다. 이미지 크기에 따라 셀의 높이는 유동적이다. 이렇게 그대로 사용하면 좋겠지만, 만약 이미지의 크기가 너무 큰 경우를 생각하자.

 

그런 경우, 셀의 높이는 매우 커져서 화면을 거의 채워버리거나 하는 것이다.

이럴 때 필요한건 셀의 높이를 개발자가 직접 지정하고 싶다는 것이다.

이런 경우 아래의 코드를 사용한다.

 

[코드]

 

Cell을 상속받는 클래스에서 작성한다.

@IBOutlet weak var ivMedia: UIImageView!

	internal var aspectConstraint: NSLayoutConstraint? {
        didSet{
            if oldValue != nil{
                ivMedia.removeConstraint(oldValue!)
            }
            if aspectConstraint != nil{
                ivMedia.addConstraint(aspectConstraint!)
            }
        }
    }
    
    ...
    
    override func prepareForReuse() {
        aspectConstraint = nil
    }
    
    ...
    
    func setIvMedia(image: UIImage){
        let aspect = image.size.width / image.size.height
        aspectConstraint = NSLayoutConstraint(item: ivMedia, attribute: .width, relatedBy: .equal, toItem: ivMedia, attribute: .height, multiplier: aspect, constant: 0)
        ivMedia.image = image
    }

NSLayoutConstraint 타입의 변수 하나를 선언하고, 해당 변수에서는 oldValue가 있다면(해당 값은 didSet에 있는 변수)초기화 하는 등의 작업을 수행한다.

 

해당 용어 공부하기

https://medium.com/ios-development-with-swift/프로퍼티-get-set-didset-willset-in-ios-a8f2d4da5514

 

중요한 것은 setIvMedia에서 보면 된다. 넘겨받은 이미지의 너비/높이의 비율을 계산하여, 해당 사이즈에 맞게 이미지의 constraint를 조절한다. 이렇게하면 automaticDimension으로 설정된 셀이라도, 높이를 직접 지정할 수 있다.

 

출처

 

https://stackoverflow.com/questions/26041820/auto-layout-get-uiimageview-height-to-calculate-cell-height-correctly