Изменить высоту размера содержимого UICollectionView на основе высоты UITableViewCell.

Я работаю над календарем, созданным с помощью UICollectionView.

UICollectionView находится внутри UITableViewCell UITableViewCell в методе heightForRowAt return UITableView.automaticDimension

UICollectionView, используемый для создания календаря, обновляет свою высоту в зависимости от того, сколько дней отображается, например, ноябрь имеет первый день, выпадающий на воскресенье, поэтому для размещения день под меткой Воскресенье к collectionView нужно обязательно добавить целую строку.

Обычно каждый месяц состоит из 5 строк (неделя), но когда первый день месяца приходится на воскресенье, collectionview возвращает 6

Теперь, как я уже сказал, я смог обновить высоту UICollectionView в зависимости от того, сколько строк он возвращает, но я не могу динамически изменить высоту элемента TableViewCell, содержащего collectionView.

Как я могу изменить размер tableViewCell на основе высоты CollectionView внутри него?


ИЗМЕНИТЬ

мой сотовый

введите здесь описание изображения


Я установил UITableView.automaticDimension для высоты ячейки, содержащей CalendarView

введите здесь описание изображения

В классе CalendarView: UIView я создал переменную CGFloat calendarH, чтобы задать высоту по умолчанию для collectionView.

введите здесь описание изображения

Реализация CollectionView

введите здесь описание изображения

Я добавил наблюдателя, который отслеживает высоту collctionView при ее изменении.

введите здесь описание изображения

В настоящее время я могу изменить высоту collectionView, но его супервизор (bookingCalendarView) и ячейка tableView продолжают оставаться с фиксированной высотой и не адаптируются к collectionView


person kAiN    schedule 10.11.2020    source источник
comment
Как вы устанавливаете высоту представления вашей коллекции?   -  person DonMag    schedule 11.11.2020
comment
@DonMag я не устанавливал фиксированную высоту .. я поместил верхнюю, ведущую, конечную и нижнюю привязку в ячейку   -  person kAiN    schedule 11.11.2020
comment
OK — представление коллекции не имеет внутренней высоты. Если вы знаете, что ваша высота строки, скажем, 20... и у вас есть 5 строк, представление коллекции требует ограничения высоты 100 (плюс интервал, если он у вас есть)... если у вас есть 6 строк, представление коллекции требует ограничение по высоте 120 (плюс интервал, если он у вас есть).   -  person DonMag    schedule 11.11.2020
comment
@DonMag У меня есть collectionView с 6 ячейками (я ввел максимальную высоту, которую достигает collectionView .. когда, например, первый день недели приходится на воскресенье). Высота составляет 450 (75 (ячейка) x 6 строк), но когда collectionView изменяет количество строк, tableviewcell не обновляет свой размер. Я добавил фотографию xib, чтобы показать вам ограничения, которые я ввел.   -  person kAiN    schedule 11.11.2020


Ответы (1)


Вам нужно создать @IBOutlet для ограничения высоты представления вашей коллекции.

Когда вы устанавливаете данные календаря/месяца строки, определите, нужны ли вам 5 или 6 строк.

Если это 6, установите .constant ограничения высоты на 750

Если это 5, установите .constant ограничения высоты на 675


Изменить

Во-первых, я предлагаю вам забыть об использовании представления коллекции с автоматически изменяющимся размером. UICollectionView предназначен для размещения ячеек в зависимости от размера представления коллекции, обеспечивая автоматическую прокрутку, когда ячеек слишком много.

Попытка изменить его размер может работать в одном случае, но не работать в другом. Причина, по которой это не удается в этом случае, заключается в том, что ваше табличное представление размещает ячейку и вычисляет ее высоту до представления коллекции и, следовательно, до того, как оно сможет изменить свой размер.

Вместо этого, поскольку вы знаете, что высота вашей ячейки равна 75, вы можете рассчитать, сколько строк потребуется вашему календарю, и либо установить .constant для ограничения высоты для вашего представления коллекции, либо (поскольку вы уже используете heightForRowAt) вычислить там высоту строки .

Посмотрите на этот код:

let dateComponents = DateComponents(year: year, month: month)
        
// startDate will be the first date of the month (Jan 1, Feb 1, Mar 1, etc...)
guard let startDate = calendar.date(from: dateComponents) else {
    fatalError("Something is wrong with the date!")
}
// get the range of days in the month
guard let range = calendar.range(of: .day, in: .month, for: startDate) else {
    fatalError("Something is wrong with the date!")
}
        
// get number of days in the month
let numberOfDaysInMonth = range.count
        
// get the day of the week for the first date in the month
//  this returns 1-based numbering
//  Nov 1, 2020 was a Sunday, so this would return 1
let startDayOfWeek = Calendar.current.component(.weekday, from: startDate)
        
// add the "leading days to the start date"
//  so, if startDayOfWeek == 3 (Tuesday)
//  we need to add 2 "empty day cells" for Sunday and Monday
let totalCellsNeeded = numberOfDaysInMonth + (startDayOfWeek - 1)
        
// calculate number of rows needed -- this will be 4, 5 or 6
//  the only time we get 4 is if Feb 1st in a non-leapYear falls on a Sunday
let numRows = Int(ceil(Double(totalCellsNeeded) / Double(7)))
        
// we now know the Height needed for the collection view
//  you said your calendar cell height is 75, so...
//  cvHeight = numRows * 75

Мы можем поместить это в цикл и print() передать информацию в консоль отладки следующим образом:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let calendar = Calendar.current

    // 2026 is the next year where Feb starts on a Sunday
    //  so let's use that year to see that we get 4 rows for Feb
    let year = 2026
    
    for month in 1...12 {
        
        let dateComponents = DateComponents(year: year, month: month)
        
        // startDate will be the first date of the month (Jan 1, Feb 1, Mar 1, etc...)
        guard let startDate = calendar.date(from: dateComponents) else {
            fatalError("Something is wrong with the date!")
        }
        // get the range of days in the month
        guard let range = calendar.range(of: .day, in: .month, for: startDate) else {
            fatalError("Something is wrong with the date!")
        }
        
        // get number of days in the month
        let numberOfDaysInMonth = range.count
        
        // get the day of the week for the first date in the month
        //  this returns 1-based numbering
        //  Nov 1, 2020 was a Sunday, so this would return 1
        let startDayOfWeek = Calendar.current.component(.weekday, from: startDate)
        
        // add the "leading days to the start date"
        //  so, if startDayOfWeek == 3 (Tuesday)
        //  we need to add 2 "empty day cells" for Sunday and Monday
        let totalCellsNeeded = numberOfDaysInMonth + (startDayOfWeek - 1)
        
        // calculate number of rows needed -- this will be 4, 5 or 6
        //  the only time we get 4 is if Feb 1st in a non-leapYear falls on a Sunday
        let numRows = Int(ceil(Double(totalCellsNeeded) / Double(7)))
        
        // we now know the Height needed for the collection view
        //  you said your calendar cell height is 75, so...
        //  cvHeight = numRows * 75
        
        // debug output
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "EEEE"
        let dayName = dateFormatter.string(from: startDate)
        dateFormatter.dateFormat = "LLLL y"
        let dateString = dateFormatter.string(from: startDate)
        
        let dayPadded = dayName.padding(toLength: 10, withPad: " ", startingAt: 0)
        let datePadded = dateString.padding(toLength: 16, withPad: " ", startingAt: 0)

        print("\(datePadded) has \(numberOfDaysInMonth) days, starting on \(dayPadded) requiring \(numRows) rows")
        
    }
    
}

Вот результат:

January 2026     has 31 days, starting on Thursday   requiring 5 rows
February 2026    has 28 days, starting on Sunday     requiring 4 rows
March 2026       has 31 days, starting on Sunday     requiring 5 rows
April 2026       has 30 days, starting on Wednesday  requiring 5 rows
May 2026         has 31 days, starting on Friday     requiring 6 rows
June 2026        has 30 days, starting on Monday     requiring 5 rows
July 2026        has 31 days, starting on Wednesday  requiring 5 rows
August 2026      has 31 days, starting on Saturday   requiring 6 rows
September 2026   has 30 days, starting on Tuesday    requiring 5 rows
October 2026     has 31 days, starting on Thursday   requiring 5 rows
November 2026    has 30 days, starting on Sunday     requiring 5 rows
December 2026    has 31 days, starting on Tuesday    requiring 5 rows

Итак... либо в:

  • cellForRowAt ... рассчитать необходимую высоту и задать высоту CV в ячейке, или
  • heightForRowAt ... вычислить и вернуть необходимую высоту строки

Боковое примечание: я бы предложил использовать авто-макет для всех ваших ячеек вместо того, чтобы возвращать различную высоту строк.

person DonMag    schedule 11.11.2020
comment
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат. - person Samuel Liew♦; 21.11.2020