Как динамически добавлять виды / слои в горизонтальном collectionView с помощью indexPath - PullRequest
0 голосов
/ 06 июня 2018

Я делаю временную шкалу сортировки с горизонтальным collectionView, где для каждого блока времени (месяца) у меня есть ячейка с UIViews для каждого дня с разными цветами.В некоторые месяцы добавлено 30 просмотров, 31 - 28. У меня возникли проблемы с динамическим добавлением представлений в каждую ячейку, чтобы они не дублировались или добавлялись не в ту ячейку.

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

Я сделал этот проект как самый простой пример того, о чем я говорю:

https://github.com/AlexMarshall12/testTimeline-iOS

Вот код в ViewController.swift:

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    var filledCells: [Int] = []

    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.filledCells = [1,28]
        collectionView.delegate = self
        collectionView.dataSource = self
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 28
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! MyCollectionViewCell
        print(indexPath.item)
        cell.myLabel.text = String(indexPath.item)
        if filledCells.contains(indexPath.item) {
            let tickLayer = CAShapeLayer()
            tickLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.layer.bounds.width, height: cell.layer.bounds.height), cornerRadius: 5).cgPath
            tickLayer.fillColor = UIColor(red:0.99, green:0.13, blue:0.25, alpha:0.5).cgColor
            cell.layer.addSublayer(tickLayer)
        } else {

        //updated 

            let tickLayer = CAShapeLayer()
            tickLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.layer.bounds.width, height: cell.layer.bounds.height), cornerRadius: 5).cgPath
            tickLayer.fillColor = UIColor(red:0.1, green:0.13, blue:0.98, alpha:0.5).cgColor
            cell.layer.addSublayer(tickLayer)
        }
        return cell
    }

}

Идея состоит в том, что для каждого элемента indexPath (каждой ячейки?) Он проверяет, содержится ли он в массиве self.filledCells: 1 или 28, которые являются внешними краями, поскольку возвращаются 28 ячеекдля номераOfItemsInSection и 1 раздела.Поэтому я хотел, чтобы каждая ячейка была светло-синей, за исключением первой и 28-й - светло-красной.

Однако, как вы можете видеть здесь https://imgur.com/a/KTLn7Cb. Есть несколько оттенков синего, красного и пурпурного, когда ячейки заполняются несколько раз, когда я прокручиваю взад и вперед, конечно, кроме 1 и 28.

Я думаю, что есть две проблемы.

  1. Каким-то образом indexPath.item возвращает 1 или 28, даже если я не прокручиваюсь до самых крайних ячеек.Почему это?
  2. Когда я снова обращаюсь к уже отрисованным ячейкам, он перерисовывает их.Я не уверен, почему это так.Мне было интересно, может ли помочь переопределение prepareForReuse (), но я слышал, что это часто плохая идея, поэтому я не уверен, что это то, что я ищу.

Любой совет по достижению этого?

Ответы [ 4 ]

0 голосов
/ 15 июня 2018

В дополнение к тому, что @Owen Hartnett говорит о возможности повторного использования ячеек, я хотел бы отметить, что вы каждый раз воссоздаете слои!Это эквивалентно созданию подпредставлений.

Каждый раз, когда вы сталкиваетесь с ячейкой внутри cellForItemAt функции, вы также должны проверить наличие предварительно добавленных слоев.Нечто подобное (не синтаксически совершенный Swift, а псевдокод):

let bLayerFound = false;
for (layer: CALayer in cell.layer.sublayers)
{
   if (layer.name.equals("mylayer"))
   {
     let shapeLayer = layer as! CAShapeLayer
     bLayerFound = true;
     //set layer properties based on your business logic, as you don't know what this cell is holding due to reuse
     shapeLayer.path = //path
     shapeLayer.fillColor = //color
   }
}

if (bLayerFound == false)
{
   //create layer here, again
   let tickLayer = CAShapeLayer()

   //set layer properties based on your business logic, as you don't know what this cell is holding due to reuse
   tickLayer.path = //path
   tickLayer.fillColor = //color
   tickLayer.name = "mylayer"
   cell.layer.addSublayer(tickLayer)     
}

Пара других предостережений:

  • Лучше всегда добавлять пользовательский интерфейс к cell.contentView, а не cell себя.
  • Как только вы запустите его, рассмотрите возможность перемещения этого кода в ваш подкласс UICollectionViewCell.Если подкласса нет, может быть, отдельная функция, чтобы не загромождать cellForItemAt грязной логикой if-else.
0 голосов
/ 08 июня 2018

Всегда плохая идея добавлять представление или слой каждый раз в ячейки табличного представления или ячейки представления коллекции.Поскольку вы повторно используете ячейки, нет необходимости создавать tickLayer снова и снова.Сделайте tickLayer глобальной переменной, инициализируйте ее в функции awakeFromNib в MyCollectionViewCell, затем измените цвет заливки в функции cellForRow.

0 голосов
/ 11 июня 2018

Добавление / удаление представлений в ячейку не очень хорошая идея.Есть два способа закончить это: ① создать разные ячейки по их подвидам;② Создайте общую ячейку и управляйте отображением подпредставления через скрытый и макет и обновляйте, когда вы получите эту ячейку с новыми данными.

0 голосов
/ 06 июня 2018

Вы упускаете из виду тот факт, что клетки используются повторно.Когда вы меняете ячейку fillColor, и она прокручивается, ячейка, которая прокручивается при прокрутке, повторно использует эту ячейку, и вы просто установили ее цвет заливки на красный, и вы не выключили ее.Установите явно fillColor для каждой ячейки, будь то красный, белый или прозрачный цвет, не устанавливайте его только для выбранных ячеек.

...