- This topic has 4개 답변, 3명 참여, and was last updated 4 years, 6 months 전에 by 멍단비.
-
글쓴이글
-
-
인담참가자
- 글작성 : 9
- 답글작성 : 9
안녕하세요.
이번 프로젝트에서 구현해야하는 내용 중 어려움이 생겨 질문을 드립니다.
프로젝트에서 요구하는 사항은 다음과 같습니다.
- 화면 진입시 외부 이미지 경로(url) 리스트가 포함된 데이터를 호출
- 각 TableViewCell에 해당 외부 이미지 경로의 이미지를 그릴 수 있는 ImageView 구현
여기서 제가 겪은 어려움은 외부 이미지의 크기(픽셀 사이즈)가 다르기 때문에 TableView의 Content 영역을 미리 계산할 수 없다는 게 문제입니다.
현재까지 제가 구현한 방식은 다음과 같습니다.
- url로 받아온 데이터를 ImageView에 그린다.(kingfisher 사용)
-
받아온 데이터(image)의 크기를 통해 가로세로 비율을 구한다.
-
해당 가로세로 비율을 ImageView의 constraint로 autolayout을 구성한다.
해당 코드로 구현할 시 나타나는 문제점은 cell이 재사용될 때 constraint가 충돌하는 경고 코드가 발생하고
이미 한번 그려진 cell( 화면에 나타난 cell)은 이미지가 불러와도 cell을 다시 그리지 않는다.(이미지 높이가 0이라서 이미지가 나타나지 않는다.)
해당 문제를 해결하려면 어떻게 해야할까요?
아래에 코드 첨부하겠습니다.
미리 감사드립니다.
class ImageTableViewCell: UITableViewCell{
var viewModel: TimeLineInfo.TimeLinesInfo.ItemInfo?{
didSet{
setCellValue()
}
}
var imageConstraint: NSLayoutConstraint?{
didSet(oldVal){
if let old = oldVal{
mainImageView.removeConstraint(old)
}
if let imageConstraint = imageConstraint{
mainImageView.addConstraint(imageConstraint)
}
}
}
let titleLabel: UILabel = {
let aLabel = UILabel()
aLabel.text = ” ”
aLabel.numberOfLines = 0
aLabel.textColor = .black
aLabel.font = .systemFont(ofSize: CGFloat(17).sizeFitWidthDevice, weight: .medium)
aLabel.translatesAutoresizingMaskIntoConstraints = false
return aLabel
}()
let mainImageView: UIImageView = {
let aImageView = UIImageView()
aImageView.layer.cornerRadius = CGFloat(20).sizeFitWidthDevice
aImageView.addBorder(borderWidth: 2, borderColor: ColorConstant.ContentColor.cLightGray)
aImageView.clipsToBounds = true
aImageView.contentMode = .scaleAspectFit
aImageView.translatesAutoresizingMaskIntoConstraints = false
return aImageView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .white
setupContentView()
}
required init?(coder: NSCoder) {
fatalError(“init(coder:) has not been implemented”)
}
private func setupContentView(){
contentView.addSubview(titleLabel)
contentView.addSubview(mainImageView)
setupLayout()
}
private func setupLayout(){
let circleView = UIView()
circleView.backgroundColor = .white
circleView.layer.cornerRadius = CGFloat(6).sizeFitWidthDevice
circleView.addBorder(borderWidth: 2, borderColor: ColorConstant.ContentColor.cMiddleGray)
circleView.translatesAutoresizingMaskIntoConstraints = false
circleView.widthAnchor.constraint(equalToConstant: CGFloat(12).sizeFitWidthDevice).isActive = true
circleView.heightAnchor.constraint(equalToConstant: CGFloat(12).sizeFitWidthDevice).isActive = true
let grayVerLine = UIView()
grayVerLine.backgroundColor = ColorConstant.ContentColor.cLightGray
grayVerLine.translatesAutoresizingMaskIntoConstraints = false
grayVerLine.widthAnchor.constraint(equalToConstant: CGFloat(1).sizeFitWidthDevice).isActive = true
contentView.addSubview(grayVerLine)
contentView.addSubview(circleView)
NSLayoutConstraint.activate([
circleView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: CGFloat(24).sizeFitWidthDevice),
circleView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: CGFloat(24).sizeFitWidthDevice),
grayVerLine.centerXAnchor.constraint(equalTo: circleView.centerXAnchor),
grayVerLine.topAnchor.constraint(equalTo: contentView.topAnchor),
grayVerLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
titleLabel.centerYAnchor.constraint(equalTo: circleView.centerYAnchor),
titleLabel.leadingAnchor.constraint(equalTo: circleView.trailingAnchor, constant: CGFloat(15).sizeFitWidthDevice),
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: CGFloat(-24).sizeFitWidthDevice),
mainImageView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: CGFloat(15).sizeFitWidthDevice),
mainImageView.leadingAnchor.constraint(equalTo: circleView.trailingAnchor, constant: CGFloat(15).sizeFitWidthDevice),
mainImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: CGFloat(-24).sizeFitWidthDevice),
mainImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: CGFloat(-24).sizeFitWidthDevice),
])
}
func setCellValue(){
titleLabel.text = viewModel?.data.text
imageConstraint?.isActive = false
//이미지가 로드된 후 클로저 호출
if let image = viewModel?.data.imageUrl{
mainImageView.setImageCacheWithConstraint(with: image) {[weak self] (result) in
switch result{
case .success(let image):
self?.imageConstraint = self?.mainImageView.heightAnchor.constraint(equalTo: (self?.mainImageView.widthAnchor)!, multiplier: image.size.height/image.size.width)
self?.imageConstraint?.isActive = true
self?.contentView.setNeedsLayout()
self?.contentView.layoutIfNeeded()
break
case .failure(_):
break
}
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
imageConstraint?.isActive = false
imageConstraint = nil
mainImageView.image = nil
}
}
2020-06-09 오후 5:13 #8920 -
야곰키 마스터
- 글작성 : 37
- 답글작성 : 579
이미지뷰의 제약을 변경한 후 contents view가 아니라 cell에게 setNeedsLayout과 layoutIfNeeded 메서드를 호출해 보실래요?
만약 그래도 안된다면
cellForRowAt indexPath
메서드 안에서cell.setNeedsLayout()
을 호출해보세요.이 글을 참고해보세요.
더 자세히 알고 싶다면 WWDC 2018 – High Performance Auto Layout영상을 한 번 보면 좋을듯합니다.
2020-06-09 오후 7:04 #8935
-
-
글쓴이글
- 답변은 로그인 후 가능합니다.