jxxnnee
jxxnnee

Reputation: 3

Can not Select CollectionView in TableView Cell

I'm making a calendar.

I put the collection view in the table view, but the cell of the collection view is not selected.

I just added the collection view to the table view cell and set all the dataSource settings.

TableView allowSelection is turned off, and tableViewCell isUserInteractionEnabled is set to false.

here for my code

CalanderView.swift

import Foundation
import UIKit

class CalendarView: UIView {
    private var increaseYear: Int = 0
    
    internal lazy var tableView: UITableView = {
        let table = UITableView()
        table.showsVerticalScrollIndicator = false
        table.translatesAutoresizingMaskIntoConstraints = false
//        table.allowsSelection = false
        table.register(CalendarCell.self, forCellReuseIdentifier: CalendarCell.reuseIdentifier)
        table.delegate = self
        table.dataSource = self
        table.bounces = false
        table.tableFooterView = UIView(
            frame: CGRect(
                x: 0,
                y: 0,
                width: self.frame.width,
                height: 120.calculated
            )
        )
//        table.estimatedRowHeight = 600.calculated
        
        return table
    }()
    
    internal lazy var header: CalendarHeader = {
        let header = CalendarHeader(frame: self.frame)
        header.backgroundColor = .white
        
        return header
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)

        setLayoutConstraints()
    }
    
    required init(coder: NSCoder) {
        super.init(coder: coder)!
        
        setLayoutConstraints()
    }
}





// MARK: -CUSTOM FUNCTION
extension CalendarView {
    func getCurrentMonth(_ val: Int) -> Int {
        let obj = CalendarHelper.today.month + val
        let currentMonth = obj % 12 == 0 ? 12 : obj % 12
        let floatVal: Float = Float(obj) / 12.0
        let ceilVal = ceil(floatVal - 1)
        
        self.increaseYear = Int(ceilVal)
        
        return currentMonth
    }
}





// MARK: -DELEGATES, DATASOURCE
extension CalendarView: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 6
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: CalendarCell = tableView.dequeueReusableCell(for: indexPath)
        let currentMonth = getCurrentMonth(indexPath.row)
        let currentYear = CalendarHelper.today.year + self.increaseYear
        let component = DateComponents(year: currentYear, month: currentMonth)
        let days = CalendarHelper.shared.daysOfMonth[currentMonth-1]
        let dayOfMonth = CalendarHelper.dateFrom(component).isLeapMonth ? days + 1 : days
        
        cell.isUserInteractionEnabled = false
        cell.month = currentMonth
        cell.year = currentYear
        cell.dayOfWeek = CalendarHelper.dateFrom(component).weekday
        cell.dayOfMonth = dayOfMonth
        cell.separatorInset = UIEdgeInsets(top: 0, left: 20.calculated, bottom: 0, right: 20.calculated)
        
        cell.bringSubviewToFront(cell.dayCollection)
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return 550
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 550
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("tableView didSelectRowAt")
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let indexPath = self.tableView.indexPathsForVisibleRows {
            if indexPath.indices.contains(1) {
                let cell = tableView.cellForRow(at: indexPath[1]) as! CalendarCell
                if scrollView.contentOffset.y > cell.frame.origin.y - 10 {
                    self.header.month = cell.month
                    self.header.year = cell.year
                }
                
                let beforeCell = tableView.cellForRow(at: indexPath[0]) as! CalendarCell
                if scrollView.contentOffset.y < cell.frame.origin.y - 10 {
                    self.header.month = beforeCell.month
                    self.header.year = beforeCell.year
                }
            }
        }
        
    }
}




// MARK: -SET LAYOUT
extension CalendarView {
    func setLayoutConstraints() {
        setTableViewLayout()
        setHeaderViewLayout()
    }
    
    func setTableViewLayout() {
        self.addSubview(self.tableView)
        self.tableView.snp.makeConstraints({
            $0.top.bottom.left.right.equalTo(self)
        })
    }
    
    func setHeaderViewLayout() {
        self.addSubview(self.header)
        self.header.snp.makeConstraints({
            $0.left.right.top.equalTo(self)
            $0.height.equalTo(90.calculated)
        })
    }
}


class CalendarHeader: UIView {
    var year: Int = 0 {
        willSet(newVal) {
            self._year.attributedText = String(newVal)
                .normal(fontSize: 16, color: Color.customer, spacing: -0.07)
        }
    }
    
    var month: Int = 0 {
        willSet(newVal) {
            let str = String(newVal) + "."
            self._month.attributedText = str
                .systemFont(fontSize: 28, weight: .semibold, color: Color.customer, spacing: -0.12)
        }
    }
    
    private var _year: UILabel = {
        let label = UILabel()
        label.attributedText = "2019"
            .normal(fontSize: 16, color: Color.customer, spacing: -0.07)
        
        return label
    }()
    
    private var _month: UILabel = {
        let label = UILabel()
        label.attributedText = "11."
            .systemFont(fontSize: 28, weight: .semibold, color: Color.customer, spacing: -0.12)
        
        return label
    }()
    
    private var chevron: UIImageView = {
        let imageView = UIImageView()
        imageView.image = #imageLiteral(resourceName: "chevron_bottom")
        imageView.contentMode = .scaleAspectFit
        imageView.clipsToBounds = true
        
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setLayoutConstraints()
        
        defer {
            self.year = CalendarHelper.today.year
            self.month = CalendarHelper.today.month
        }
    }
    
    required init(coder: NSCoder) {
        super.init(coder: coder)!
        
        setLayoutConstraints()
        defer {
            self.year = CalendarHelper.today.year
            self.month = CalendarHelper.today.month
        }
    }
    
    func setLayoutConstraints() {
        self.addSubview(self._year)
        self._year.snp.makeConstraints({
            $0.left.equalTo(self).offset(20.calculated)
            $0.top.equalTo(self).offset(41.calculated)
        })
        
        self.addSubview(self._month)
        self._month.snp.makeConstraints({
            $0.left.equalTo(self._year.snp.right).offset(4.calculated)
            $0.top.equalTo(self).offset(28.calculated)
        })
        
        self.addSubview(self.chevron)
        self.chevron.snp.makeConstraints({
            $0.width.height.equalTo(CGSize.ratio(width: 26, height: 14))
            $0.right.equalTo(self).offset(-20.calculated)
            $0.centerY.equalTo(self._month)
        })
    }
}

CalanderCell.swift

import Foundation
import UIKit
import SnapKit

class CalendarCell: UITableViewCell {
    let weekdays = ["S", "M", "T", "W", "T", "F", "S"]
    var dayOfWeek = 0
    var dayOfMonth = 0
    var day = 0
    
    var year: Int = 0 {
        willSet(newVal) {
            self._year.attributedText = String(newVal)
                .normal(fontSize: 16, color: Color.customer, spacing: -0.07)
        }
    }
    
    var month: Int = 0 {
        willSet(newVal) {
            let str = String(newVal) + "."
            self._month.attributedText = str
                .systemFont(fontSize: 28, weight: .semibold, color: Color.customer, spacing: -0.12)
        }
    }
    
    internal var _year: UILabel = {
        let label = UILabel()
        label.attributedText = "2019"
            .normal(fontSize: 16, color: Color.customer, spacing: -0.07)
        
        return label
    }()
    
    internal var _month: UILabel = {
        let label = UILabel()
        label.attributedText = "11."
            .systemFont(fontSize: 28, weight: .semibold, color: Color.customer, spacing: -0.12)
        
        return label
    }()
    
    internal var dayCollection: UICollectionView = {
        let collectionViewLayout = UICollectionViewFlowLayout()
        collectionViewLayout.scrollDirection = .vertical
        
        let collection = UICollectionView(
            frame: CGRect(x: 0, y: 0, width: 0, height: 0),
            collectionViewLayout: collectionViewLayout
        )
        collection.showsVerticalScrollIndicator = false
        collection.showsHorizontalScrollIndicator = false
        collection.isMultipleTouchEnabled = false
        collection.allowsMultipleSelection = false
        collection.isScrollEnabled = false
        collection.isExclusiveTouch = true
        collection.isUserInteractionEnabled = true
        collection.backgroundColor = Color.background
        collection.register(DayCell.self, forCellWithReuseIdentifier: DayCell.reuseIdentifier)
        
        
        return collection
    }()
    
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        setLayoutConstraints()
        
        
        dayCollection.delegate = self
        dayCollection.dataSource = self
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}





extension CalendarCell {

}





extension CalendarCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    /// 지정된 섹션에 표시할 항목의 개수를 묻는 메서드
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if section == 0 {
            return 7
        } else {
            print("dayOfWeek", dayOfMonth)
            return dayOfMonth + dayOfWeek - 1
        }
    }
    
    /// 컬렉션뷰의 지정된 위치에 표시할 셀을 요청하는 메서드.
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell: DayCell = collectionView.dequeueReusableCell(for: indexPath)
        cell.isUserInteractionEnabled = true
        
        if indexPath.section == 0 {
            cell.week = weekdays[indexPath.row]
        } else {
            if dayOfWeek > 1 {
                cell.day = ""
                dayOfWeek -= 1
            } else {
                day += 1
                cell.day = String(day)
                cell.isSunday = indexPath.row % 7 == 0
            }
        }
        
        return cell
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
    
    /// 지정된 섹션의 여백을 반환하는 메서드.
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 25.calculated, bottom: 25.calculated, right: 25.calculated)
    }
    
    /// 지정된 섹션의 행 사이 간격 최소 간격을 반환하는 메서드
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 25
    }
    
    /// 지정된 섹션의 셀 사이의 최소간격을 반환하는 메서드.
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 25
    }
    
    /// 지정된 셀의 크기를 반환하는 메서드
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize.ratio(width: 30, height: 30)
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("indexPath: ", indexPath)
    }
}



extension CalendarCell {
    func setLayoutConstraints() {
        setHeaderLayout()
        setDayCollectionLayout()
    }
    
    func setHeaderLayout() {
        self.addSubview(self._year)
        self._year.snp.makeConstraints({
            $0.left.equalTo(self).offset(20.calculated)
            $0.top.equalTo(self).offset(61.calculated)
        })
        
        self.addSubview(self._month)
        self._month.snp.makeConstraints({
            $0.left.equalTo(self._year.snp.right).offset(4.calculated)
            $0.top.equalTo(self).offset(48.calculated)
        })
    }
    
    func setDayCollectionLayout() {
        self.addSubview(self.dayCollection)
        self.dayCollection.snp.makeConstraints({
            $0.height.equalTo(400.calculated)
            $0.left.right.equalTo(self)
            $0.top.equalTo(self).offset(116.calculated)
        })
    }
}

DayCell.swift

import Foundation
import UIKit

class DayCell: UICollectionViewCell {
    var isSunday: Bool = false {
        willSet(newVal) {
            self._day.textColor = newVal ? Color.customer : Color.label
        }
    }
    var isReserved: Bool = false {
        willSet(newVal) {
            self._day.textColor = Color.cancle
        }
    }
//    override var isSelected: Bool {
//        willSet(newVal) {
//            self.backgroundColor = newVal
//                ? Color.customer
//                : Color.background
//            self._day.textColor = newVal
//                ? .white
//                : (isSunday ? Color.customer : Color.label)
//        }
//    }
    var day: String = "" {
        willSet(newVal) {
            self._day.attributedText = newVal
                .systemFont(fontSize: 18, weight: .bold, color: Color.label, spacing: -0.07)
        }
    }
    var week: String = "" {
        willSet(newVal) {
            self._day.attributedText = newVal
                .systemFont(fontSize: 20, weight: .medium, color: Color.customer, spacing: -0.08)
        }
    }
    
    internal var _day: UILabel = {
        let label = UILabel()
        label.attributedText = "1"
            .systemFont(fontSize: 18, weight: .bold, color: Color.label, spacing: -0.07)
        
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.layer.cornerRadius = 7.calculated
        self.addSubview(self._day)
        self._day.snp.makeConstraints({
            $0.center.equalTo(self)
        })
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Upvotes: 0

Views: 643

Answers (1)

matt
matt

Reputation: 535915

This is wrong:

class DayCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.layer.cornerRadius = 7.calculated
        self.addSubview(self._day) // <-- NO
        self._day.snp.makeConstraints({
            $0.center.equalTo(self)
        })
    }
}

Never add a subview to a cell. Say

self.contentView.addSubview(self._day)

Otherwise it is impossible to touch the _day interface.

Upvotes: 1

Related Questions