UICollectionViewCell - Применение разных CAGradientLayer к разным UIView

TL; DR: есть 2 представления (верхнее и нижнее), для которых требуется CAGradientLayer. Неожиданным поведением является то, что только вид сверху отображает градиент. Внизу не отображается градиент.

В нашем приложении у меня есть представление с UICollectionView, как показано на изображении: Все устройство

Для каждого UICollectionViewCell я создал собственный класс для деталей макета. В UICollectionViewCell у меня есть «topBackground» и «bottomBackground», которые представляют собой представления, которые будут содержать метки с информацией для каждой ячейки:

@IBOutlet weak var topBackground: UIView! 
@IBOutlet weak var bottomBackground: UIView!

Виды сверху и снизу, метки отображались правильно, и ограничения работали.

Мы решили добавить эффект градиента в вид сверху и снизу (см. Подробности на изображении, верхний градиент отмечен красным, а нижние детали отмечены желтым)  введите описание изображения здесь .

Для кода мы использовали следующее:

override func layoutSubviews() {
        if !didLayout{                
             // Top View
            let gradientLayer: CAGradientLayer = CAGradientLayer()
            gradientLayer.frame = topBackground.frame
            gradientLayer.colors =
                [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0).cgColor]
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.9)
            topBackground.layer.insertSublayer(gradientLayer, at: 0)
            topBackground.backgroundColor = .clear
            topBackground.alpha = 0.5

            // Bottom View
            let gradientLayerBottom: CAGradientLayer = CAGradientLayer()
            gradientLayerBottom.frame = bottomBackground.frame
            gradientLayerBottom.colors =
                [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0).cgColor]
            gradientLayerBottom.startPoint = CGPoint(x: 0.5, y: 0.9)
            gradientLayerBottom.endPoint = CGPoint(x: 0.5, y: 0)
            bottomBackground.layer.insertSublayer(gradientLayerBottom, at: 0)
            bottomBackground.backgroundColor = .clear
            bottomBackground.alpha = 0.5

            didLayout = true
        } else {
            print("already performed layout")
        }
    }

Переменная didLayout предназначена для предотвращения перекрытия нескольких градиентов при прокрутке представления коллекции.

Результаты:

  1. Вид сверху отображает градиент (ожидаемый).
  2. Нижний вид не отображает градиент (неожиданно).

Мы знаем, что существует нижний вид с рабочими ограничениями, потому что, если мы изменим цвет на отличный от .clear, он отобразит другой цвет. Просто gradientLayerBottom не отображается.

Есть идеи, как заставить gradientLayerBottom отображаться?


person Victor Sanchez    schedule 31.05.2019    source источник
comment
почему вы вставляете подслой в 0?   -  person Lu_    schedule 31.05.2019
comment
@Lu_ Пытался убедиться, что это первая позиция layer.sublayers. Также пробовал addSublayer вместо insertSublayer(at:), но результаты те же.   -  person Victor Sanchez    schedule 31.05.2019
comment
а если вы установите те же начальную и конечную точки, что и в верхнем слое градиента? это странно, код выглядит нормально   -  person Lu_    schedule 31.05.2019
comment
@Lu_ Если я установил одинаковые начальную и конечную точки, тот же результат, нижний не отображается.   -  person Victor Sanchez    schedule 31.05.2019


Ответы (1)


Попробуй это

extension UIView{
    func setGradientBackgroundImage(colorTop: UIColor, colorBottom: UIColor) {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor]
        gradientLayer.frame = bounds
        layer.insertSublayer(gradientLayer, at: 0)
    }
}

Поместите в класс UICollectionViewCell

class CollVwCell : UICollectionViewCell{

    @IBOutlet weak var VwTop: UIView!
    @IBOutlet weak var VwBottom: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        DispatchQueue.main.async {
            self.VwTop.setGradientBackgroundImage(colorTop: UIColor.red, colorBottom: UIColor.white)
            self.VwBottom.setGradientBackgroundImage(colorTop: UIColor.white, colorBottom: UIColor.purple)
        }
    }
}

Вывод:

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

person Nikunj Kumbhani    schedule 31.05.2019
comment
да, это gradientLayer.frame = bounds! Я сделал: gradientLayer.frame = topBackground.bounds и gradientLayerBottom.frame = bottomBackground.bounds в коде, который у нас есть, и это сработало. Проблема была в кадре градиентного слоя. - person Victor Sanchez; 31.05.2019
comment
Тем не менее, мне интересно, почему это сработало для верха, а не для низа ... И, кстати, забыл вызвать это на awakeFromNib, поэтому мне не нужно вызывать переменную didLayout. Хорошее напоминание - person Victor Sanchez; 31.05.2019
comment
@VictorSanchez Вы устанавливаете ограничения раскадровкой или программно? - person Nikunj Kumbhani; 31.05.2019
comment
Пытался оба, чтобы увидеть, устранил ли это проблему, в конечном итоге оставил раскадровку. - person Victor Sanchez; 31.05.2019
comment
@VictorSanchez Я думаю, у вас проблема с ограничениями, потому что я пробовал то же самое, как вы применяете два разных градиента для просмотра внутри UICollectionViewCell, и он отлично работает с моим ответом. Вы также можете увидеть изображение вывода в моем обновленном ответе. - person Nikunj Kumbhani; 31.05.2019
comment
Да, ваш ответ раньше работал нормально :) Но это не было проблемой принуждения. Проблема заключалась в использовании topBackground.bound вместо topBackground.frame. - person Victor Sanchez; 31.05.2019