Как перезагрузить одну ячейку collectionView в обратном вызове willDisplayCell? - PullRequest
0 голосов
/ 11 октября 2018

У меня есть collectionView, из которого я делаю временную шкалу.В горизонтальном CollectionView есть много тонких ячеек - каждая ячейка представляет 1 день.Вот код проекта: https://github.com/AlexMarshall12/singleDayTimeline.git

Вот viewController:

let cellIdentifier = "DayCollectionViewCell"
class ViewController: UIViewController, UICollectionViewDataSource,UICollectionViewDelegate {

    @IBOutlet weak var button: UIButton!
    var dates = [Date?]()
    var startDate: Date?
    var endDate: Date?
    private var selectedIndexPath: IndexPath?

    @IBOutlet weak var daysCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        daysCollectionView.register(UINib.init(nibName: "DayCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: cellIdentifier)

        let allDates = Helper.generateRandomDate(daysBack: 900, numberOf: 10)
        self.dates = allDates.sorted(by: {
            $0!.compare($1!) == .orderedAscending
        })
        self.startDate = Calendar.current.startOfDay(for: dates.first as! Date)

        self.endDate = dates.last!
        self.dates = Array(dates.prefix(upTo: 1))
        daysCollectionView.delegate = self
        daysCollectionView.dataSource = self
    }

    var onceOnly = false

    internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        if !onceOnly {
            //let lastDateIndexPath = IndexPath(row: dates.count - 1,section: 0)
            let lastDate = dates.last
            let lastDayIndex = lastDate!?.interval(ofComponent: .day, fromDate: startDate!)
            let lastDayCellIndexPath = IndexPath(row: lastDayIndex!, section: 0)
            self.daysCollectionView.scrollToItem(at: lastDayCellIndexPath, at: .left, animated: false)
            self.selectedIndexPath = lastDayCellIndexPath
            self.daysCollectionView.reloadItems(at: [lastDayCellIndexPath])

            onceOnly = true
        }
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        let days = self.endDate!.days(from: self.startDate!)
        if days <= 150 {
            return 150
        } else {
            print(days,"days")
            return days + 1
        }
    }

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

        let cellDate = Calendar.current.date(byAdding: .day, value: indexPath.item, to: self.startDate!)

        if let selectedRow = selectedIndexPath {
            cell.reloadCell(selectedRow==indexPath)
        } else {
            cell.reloadCell(false)
        }

        if Calendar.current.component(.day, from: cellDate!) == 15 {
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "MMM"
            let monthString = dateFormatter.string(from: cellDate!)
            cell.drawMonth(month: monthString)
        }
        if Calendar.current.component(.day, from: cellDate!) == 1 && Calendar.current.component(.month, from: cellDate!) == 1 {
            print("drawYEAR")
            cell.drawYear(year:Calendar.current.component(.year, from: cellDate!))
        }
        if self.dates.contains(where: { Calendar.current.isDate(cellDate!, inSameDayAs: $0!) }) {
            print("same")
            cell.backgroundColor = UIColor.red
        }
        //cell.backgroundColor = UIColor.blue
        return cell
    }

    @IBAction func buttonPressed(_ sender: Any) {

        let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
        let randomDate = self.dates[randomIndex]
        let daysFrom = randomDate?.days(from: self.startDate!)
        let indexPath = IndexPath(row: daysFrom!, section: 0)
        self.selectedIndexPath = indexPath;

        //daysCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally)
        daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
        daysCollectionView.reloadData()
    }

}

Обратите внимание, что когда вызывается функция buttonPressed, изменяется selectedIndexPath.Затем в следующий раз, когда вызывается cellForItemAt, он выполняет cell.reloadCell, и если indexPath - это selectedIndexPath, он отображает arrowImageView (см. Ниже)

class DayCollectionViewCell: UICollectionViewCell {

    ...
    func reloadCell(_ isSelected:Bool){
        arrowImage.isHidden = !isSelected
    }

}

Это работает при нажатии кнопки, однако я пытаюсьчтобы он работал в обратном вызове willDisplayCell.Вы можете видеть, что в этом обратном вызове я в основном просто получаю самую последнюю (самую последнюю) дату и прокручиваю ее, а затем устанавливаю SelectedIndexPath в этот indexPath.Теперь мне нужен способ заставить стрелку нарисовать эту клетку.

Вот как это выглядит сейчас: enter image description here

Как вы можете видеть, стрелка не отображается, пока вы не прокрутите ее.Я думаю, что происходит то, что, когда вы прокручиваете достаточно, вызывается cellForItemAt, который, как мы знаем, работает.Но как мне заставить willDisplayCell успешно выполнить то же самое и, таким образом, загрузить стрелку при первом запуске?

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

Я добавляю новый ответ, потому что я заметил некоторые неполные детали о других ответах.

В viewDidLoad есть странный код:

 self.dates = Array(dates.prefix(upTo: 1))

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

    let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
    let randomDate = self.dates[randomIndex]
    let daysFrom = randomDate?.days(from: self.startDate!)
    let indexPath = IndexPath(row: daysFrom!, section: 0)
    self.selectedIndexPath = indexPath;
//     daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)

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

Одно место идеи такое же оригинальноепост в willDisplay, который легко реализовать.Единственная проблема заключается в том, что промежуток времени willDisplay невелик, поэтому перезагрузка всей collectionData там не может быть вызвана.

Но это хорошо для прокрутки до одного indexPath там.Так же, как следующий код.

 var onceOnly = false
 internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {

            if (!onceOnly){
            self.daysCollectionView.scrollToItem(at: self.selectedIndexPath!, at: .left, animated: false)
            onceOnly = true
            }
}

Есть еще одно хорошее место для вызова обеих функций (selectIndex и прокрутка), как в следующем месте:

    override  func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
    let randomDate = self.dates[randomIndex]
    let daysFrom = randomDate?.days(from: self.startDate!)
    let indexPath = IndexPath(row: daysFrom!, section: 0)
    if self.selectedIndexPath != nil {
      daysCollectionView.reloadItems(at: [self.selectedIndexPath!])
    }
    self.selectedIndexPath = indexPath;
     daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
     daysCollectionView.reloadItems(at: [indexPath])
}

Теперь я думаю, что этополный ответ.Надеюсь, что это полезно.

0 голосов
/ 17 октября 2018

В вашем viewDidLoad вы, кажется, инициализируете даты , startDate и endDate .

Итак,сразу после установки этих переменных вы можете установить selectedIndexPath , используя доступные данные.Затем, когда вызывается метод cellForItem , код там автоматически обрабатывает видимость вашей стрелки.

Поместите этот код сразу после инициализации 3 переменных, внутри viewDidLoad .

if let startDate = startDate,
    let lastDayIndex = dates?.last?.interval(ofComponent: .day, fromDate: startDate) {
    selectedIndexPath = IndexPath(row: lastDayIndex, section: 0)
}

Вам не нужно обрабатывать это в willDisplayCell или использовать логическое значение OnceOnly .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...