AutomaticDimension Programmatically

Zion·2021년 4월 8일
1
post-thumbnail

소개


와... 이틀간 삽질이 빛을 발했다...
오기가 생겨서 끝까지 붙잡고 있었더니 해결~!
뿌듯하니까 기록하도록한다.

음음... 내가 만들고 싶은 뷰는 말이지... CollectionView를 TableView에 넣고 싶단 말이다.
아 여기까지 들으면 쏘이지하지? 근데 조건은 CollectionView에 Cell이 몇개 들어있는지 몰라 ~ 랜덤하게 넣어줄거다.

자 그럼 '랜덤하게 넣어줄거다.'에서 벌써 Cell의 높이를 계산해서 보여줄수는 없게 된다.(몇개 들어있는지 모르니까!)
그렇담... 익히 들어왔던 UITableView.automaticDimension을 사용해야 한다.
(근데 이건 내가 써서 한번도 성공한 적이 없는거다. )

과정

자. 제목에서도 썼다시피 Programmatically하게 할거다.
Storyboard, IB~이런거 다 안쓰고 오직 코드로만 하겠단 말이다.
1차시도도 기록했으면 좋으련만 ( 결과는 delegate를 안해서 실패였다.)!

CollectionView Cell

class CollViewCell: UICollectionViewCell {
    let theLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        contentView.addSubview(theLabel)
        theLabel.textColor = .black
        theLabel.textAlignment = .center
        contentView.backgroundColor = .clear
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemnted")
    }
    
    override func layoutSubviews() {
        theLabel.translatesAutoresizingMaskIntoConstraints = false
        theLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        theLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        theLabel.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        theLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }
}

^ CollectionView에는 Label밖에 안넣어줬기 때문에 설명은 생략한다.( 저런건 Anchor보다 UIEdgeInset을 쓰던데... 다음에 공부하더록하겠다.)

DynamicTableViewCell

TableCell안에 CollectionView를 넣어줄거기 때문에 상속할것이.
UITableViewCell,
UICollectionViewDataSource,
UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout
이렇게 있다.
code로 할거기 때문에 awakenib이 필요하는지는 잘 모르겠다.
있으니까 여기에도 init해준다.

class DynCollectionViewTableViewCell: UITableViewCell,
                                     UICollectionViewDataSource,
                                     UICollectionViewDelegate,
                                     UICollectionViewDelegateFlowLayout {
//
   var theCollectionView: UICollectionView!
   var theCVHeight: NSLayoutConstraint!
   
   var vContentSize: CGSize = CGSize.zero
   var delegate : CollectionViewContentHeightDelegate?
   
   
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
       super.init(style: style, reuseIdentifier: reuseIdentifier)

       
       self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]        //self.translatesAutoresizingMaskIntoConstraints = false
       
       
       let layout = UICollectionViewFlowLayout.init()
       layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
       layout.scrollDirection = .vertical


       theCollectionView = UICollectionView.init(frame: .zero, collectionViewLayout: layout)

       theCollectionView.backgroundColor = .clear
       
       contentView.addSubview(theCollectionView)
       
       theCollectionView.delegate = self
       theCollectionView.dataSource = self
       
       commonInit()
   }
   
   required init?(coder aDecoder: NSCoder) {
       fatalError("init(coder:) has not been implemented")
   }

   override func awakeFromNib() {
       super.awakeFromNib()
       // Initialization code

       self.backgroundColor = .white
       commonInit()
       
       
   }
   
   func commonInit() {
       theCollectionView.translatesAutoresizingMaskIntoConstraints = false
       theCollectionView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 16).isActive = true
       theCollectionView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -16).isActive = true
       theCollectionView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 1).isActive = true
       theCollectionView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -1).isActive = true
       //theCollectionView.heightAnchor.constraint(equalToConstant: 50).isActive = true
       
       theCollectionView.register(CollViewCell.self, forCellWithReuseIdentifier: "cell")

       theCVHeight = theCollectionView.heightAnchor.constraint(equalToConstant: 100)
       theCVHeight!.priority = UILayoutPriority.init(999)

       theCVHeight?.isActive = true
       self.backgroundColor = .white

   }

   func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
       return 1
   }
   
   func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
   //랜덤 넘버 생성
       let t = Int(arc4random_uniform(27)) + 3
       return t
   }

   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
       
       let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollViewCell

       let c = UIColor.randomColor()

       cell.backgroundColor = c
       cell.theLabel.textColor = c.isDark ? .white : .yellow

       cell.theLabel.text = "\(indexPath.row)"
       
       if collectionView.contentSize != vContentSize {
           self.vContentSize = collectionView.contentSize
           self.theCVHeight?.constant = vContentSize.height
           print("theContent Height \(theCVHeight?.constant)")
           print("collectionView contentSize: \(collectionView.contentSize)")
           
       }
       return cell
   }
   
   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
       return CGSize(width: 100, height: 30)
   }
   
}


여기의 로그를 확인해볼까?

collectionView contenSize : (Width , Height)이다. Height가 제각각인거 확인 했나?
자 이러고 나서 ViewController가서 신나게 AutomaticDimension이랑 estimated row 설정 했다.
결과는?
.
.
.
.
.
어림도 없지^^ 호락호락할거 같냐 이놈아!
계속 cell height가 일정하게 나오더랬다...(dynamic해야 하는데...)음음 뭐가 문젤까 하다가 Simulator를 건드리는 도중. 스크롤 할수록 ? Layout이 맞춰지는게 아닌가? 아 cell이 안보였다가 보여지게 되면 업데이트가 되는걸 어디서 봤더랬다. 그래서 그런가 하고? ScrollDid함수에다가 reload() 함수와 beginUpdate, endUpdate함수를 넣었더랬다.
결과는 ? 구현되는게 영 이상하다...

그러던 중 Update Layout을 찾아 봤고

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    
    var cellHeight: CGFloat?
    private var myTableView: UITableView!

    
    //keeping track of the current open section
    private var openSection: Int = 0
    
    override func viewDidLoad() {
        
        super.viewDidLoad()
        self.navigationItem.title = "Main View"
        
        //get my sample data for loading the table view

        //setup my table view
        myTableView = UITableView()
        
        myTableView.dataSource = self
        myTableView.delegate = self
       // myTableView.isDynamicSizeRequired = true
        myTableView.register(DynCollectionViewTableViewCell.self, forCellReuseIdentifier: "cell")
        myTableView.rowHeight = UITableView.automaticDimension
        myTableView.estimatedRowHeight = 100

        myTableView.translatesAutoresizingMaskIntoConstraints = false
        myTableView.tableFooterView = UIView()
        self.view.addSubview(myTableView)
        
        
        myTableView.layer.borderWidth = 1
        myTableView.layer.borderColor = #colorLiteral(red: 0.1921568662, green: 0.007843137719, blue: 0.09019608051, alpha: 1)
        myTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        myTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -10).isActive = true
        myTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        print("my tableView contentSize : \(myTableView.contentSize)")

        
    }
    
    
    override func viewDidLayoutSubviews() {
        self.myTableView.beginUpdates()
        self.myTableView.endUpdates()
    }
    //when user taps on the row
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("select")

    }
    
    //no of sections for the table view
    func numberOfSections(in tableView: UITableView) -> Int {
        return 10
    }
    
    //number of rows for that section
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    //render the cell and display data
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? DynCollectionViewTableViewCell
        
        print("this is VC :\(cell?.frame.height)")
        

        return cell!
    }
       
}

중에서 viewDidLayoutSubView()에서 업데이트 해줬더니 잘 돌아갔단 말이다.

이번 계기를 통해서 얻게된건... NSLayoutConstraint에 원하는 값을 넣을 수 있는것과 사용할 수 있게 된거다.
Priorty에 대해서는 내가 알고 쓴게 아니고 StackOverFlow뒤지다고 이렇게 바꾸래서 바꾼거다. 200했다 999했다 1000했다 많이 고쳤다. 흠 이만 ! 안녕 !

profile
어제보다만 나아지는

0개의 댓글