Картинки исчезают при прокрутке вниз в CollectionView

#ios #swift #uicollectionview

#iOS #swift #uicollectionview

Вопрос:

У меня есть CollectionView для отображения сообщений, у меня есть 3 разных типа сообщений (текст, изображение и видео). Я добавил imageview в ячейку и использую коды if else в функции cellForItemAt для отображения imageview для постов с изображениями и видео или скрываю его с помощью heightAnchor = 0 для текстовых постов.

вначале загрузка правильная, но при прокрутке вниз и повторной прокрутке вверх изображения увеличиваются или сбрасываются на «0» для каждого сообщения. Как я могу решить эту проблему?

Когда сообщения загружены

Когда сообщения загружены

Когда я прокручиваю вниз и снова прокручиваю вверх

Когда я прокручиваю вниз и снова прокручиваю вверх

Временные записи CollectionViewCell

 class TimelinePosts: UICollectionViewCell {

    let avatar: UIImageView = {
        let avatar = UIImageView()
        avatar.contentMode = .scaleAspectFill
        avatar.clipsToBounds = true
        avatar.layer.cornerRadius = 24
        avatar.translatesAutoresizingMaskIntoConstraints = false
        return avatar
    }()

    let name: UILabel = {
        let name = UILabel()
        name.numberOfLines = 1
        name.translatesAutoresizingMaskIntoConstraints = false
        return name
    }()

    let content: ActiveLabel = {
        let content = ActiveLabel()
        content.numberOfLines = 0
        content.font = UIFont.systemFont(ofSize: 15)
        content.translatesAutoresizingMaskIntoConstraints = false
        return content
    }()

    let image: UIImageView = {
        let image = UIImageView()
        image.contentMode = .scaleAspectFill
        image.clipsToBounds = true
        image.layer.cornerRadius = 12
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()

    let time: UILabel = {
        let time = UILabel()
        time.numberOfLines = 1
        time.textColor = .gray
        time.font = UIFont.systemFont(ofSize: 14)
        time.textAlignment = .center
        time.translatesAutoresizingMaskIntoConstraints = false
        return time
    }()

    let moreButton: UIButton = {
        let button = UIButton()
        let image = UIImage(named: "arrow")
        button.setImage(image, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()


    let favoriteButton: FaveButton = {
        let button = FaveButton(frame: CGRect(x:0, y:0, width: 28, height: 28), faveIconNormal: UIImage(named: "favorite"))
        button.normalColor = UIColor(hexString: "#CBCBCB")
        button.selectedColor = UIColor(hexString: "#FFBE00")
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    let boostButton: FaveButton = {
        let button = FaveButton(frame: CGRect(x:0, y:0, width: 28, height: 28), faveIconNormal: UIImage(named: "boost-pressed"))
        button.normalColor = UIColor(hexString: "#CBCBCB")
        button.selectedColor = UIColor(hexString: "#6e00ff")
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    let actions: UILabel = {
        let view = UILabel()
        view.numberOfLines = 1
        view.textAlignment = .left
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        addViews()
        setupViews()
    }

    func addViews(){
        addSubview(avatar)
        addSubview(moreButton)
        addSubview(time)
        addSubview(name)
        addSubview(content)
        addSubview(image)
        addSubview(favoriteButton)
        addSubview(boostButton)
        addSubview(actions)

    }

    func setupViews(){

        avatar.leftAnchor.constraint(equalTo: leftAnchor, constant: 15).isActive = true
        avatar.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
        avatar.widthAnchor.constraint(equalToConstant: 48).isActive = true
        avatar.heightAnchor.constraint(equalToConstant: 48).isActive = true

        moreButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -18).isActive = true
        moreButton.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
        moreButton.widthAnchor.constraint(equalToConstant: 14).isActive = true
        moreButton.heightAnchor.constraint(equalToConstant: 14).isActive = true

        time.leftAnchor.constraint(equalTo: leftAnchor, constant: 15).isActive = true
        time.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
        time.widthAnchor.constraint(equalToConstant: 48).isActive = true
        time.heightAnchor.constraint(equalToConstant: 20).isActive = true

        name.leftAnchor.constraint(equalTo: avatar.rightAnchor, constant: 10).isActive = true
        name.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: -14).isActive = true
        name.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
        name.heightAnchor.constraint(equalToConstant: 20).isActive = true

        content.leftAnchor.constraint(equalTo: leftAnchor, constant: 73).isActive = true
        content.rightAnchor.constraint(equalTo: rightAnchor, constant: -46).isActive = true
        content.topAnchor.constraint(equalTo: name.bottomAnchor, constant: 5).isActive = true

        image.leftAnchor.constraint(equalTo: leftAnchor, constant: 73).isActive = true
        image.rightAnchor.constraint(equalTo: rightAnchor, constant: -46).isActive = true
        image.topAnchor.constraint(equalTo: content.bottomAnchor, constant: 5).isActive = true
        image.heightAnchor.constraint(equalToConstant: ((UIScreen.main.bounds.width - 120) * 2) / 3).isActive = true

        actions.leftAnchor.constraint(equalTo: avatar.rightAnchor, constant: 10).isActive = true
        actions.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: -14).isActive = true
        actions.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 10).isActive = true
        actions.heightAnchor.constraint(equalToConstant: 20).isActive = true
        actions.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true

        favoriteButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -14).isActive = true
        favoriteButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
        favoriteButton.widthAnchor.constraint(equalToConstant: 20).isActive = true
        favoriteButton.heightAnchor.constraint(equalToConstant: 20).isActive = true

        boostButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -14).isActive = true
        boostButton.bottomAnchor.constraint(equalTo: favoriteButton.topAnchor, constant: -12).isActive = true
        boostButton.widthAnchor.constraint(equalToConstant: 20).isActive = true
        boostButton.heightAnchor.constraint(equalToConstant: 20).isActive = true


       /* name.backgroundColor = .yellow
        content.backgroundColor = .red
        image.backgroundColor = .green */

    }


    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
  

И функция cellForItemAt

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

            if indexPath.row < id.count{

            cell.avatar.sd_setImage(with: URL(string: avatars[indexPath.row]))

            cell.time.text = hours[indexPath.row]

            cell.favoriteButton.isSelected = isLike[indexPath.row]
            cell.favoriteButton.isUserInteractionEnabled = true
            cell.favoriteButton.tag = indexPath.row

            cell.boostButton.isSelected = isBoost[indexPath.row]
            cell.boostButton.isUserInteractionEnabled = true
            cell.boostButton.tag = indexPath.row

            let selectedArrowTap = UITapGestureRecognizer(target: self, action: #selector(self.selectedArrow))
            selectedArrowTap.numberOfTapsRequired = 1
            cell.moreButton.isUserInteractionEnabled = true
            cell.moreButton.tag = indexPath.row
            cell.moreButton.addGestureRecognizer(selectedArrowTap)


            cell.content.customize { label in
                label.text = content[indexPath.row]
                label.hashtagColor = UIColor(hexString: "#6e00ff")
                label.mentionColor = UIColor(hexString: "#6e00ff")
                label.URLColor = UIColor(hexString: "#0366d6")
            }

            cell.content.handleHashtagTap { hashtag in
                print("Success. You just tapped the (hashtag) hashtag")
            }

            cell.content.handleURLTap { url in

                let urlString = url.absoluteString

                if urlString.hasPrefix("http://")
                {
                    let openURL = URL(string: urlString)!
                    let svc = SFSafariViewController(url: openURL)
                    self.present(svc, animated: true, completion: nil)
                }
                else if urlString.hasPrefix("https://")
                {
                    let openURL = URL(string: urlString)!
                    let svc = SFSafariViewController(url: openURL)
                    self.present(svc, animated: true, completion: nil)
                }
                else
                {
                    let openURL = URL(string: "https://"   urlString)!
                    let svc = SFSafariViewController(url: openURL)
                    self.present(svc, animated: true, completion: nil)
                }

            }



            if types[indexPath.row] == 2{
                cell.image.sd_setImage(with: URL(string: images[indexPath.row]))
                let selectedImageTap = UITapGestureRecognizer(target: self, action: #selector(self.photoZoom))
                selectedImageTap.numberOfTapsRequired = 1
                cell.image.isUserInteractionEnabled = true
                cell.image.tag = indexPath.row
                cell.image.addGestureRecognizer(selectedImageTap)

            }else if types[indexPath.row] == 3{
                cell.image.sd_setImage(with: URL(string: "https://i.ytimg.com/vi/(self.extractYoutubeIdFromLink(link: videos[indexPath.row])!)/mqdefault.jpg"))

                let playBtn = UIImageView()
                playBtn.image = UIImage(named: "youtube-play")
                playBtn.tag = indexPath.row
                playBtn.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.videoPlay)))
                playBtn.isUserInteractionEnabled = true
                playBtn.translatesAutoresizingMaskIntoConstraints = false
                cell.image.isUserInteractionEnabled = true

                cell.image.addSubview(playBtn)

                playBtn.centerXAnchor.constraint(equalTo: cell.image.centerXAnchor).isActive = true
                playBtn.centerYAnchor.constraint(equalTo: cell.image.centerYAnchor).isActive = true
                playBtn.widthAnchor.constraint(equalToConstant: 74).isActive = true
                playBtn.heightAnchor.constraint(equalToConstant: 52).isActive = true



            }else{
                cell.image.heightAnchor.constraint(equalToConstant: 0).isActive = true
            }
}

            return cell
        }
  

Комментарии:

1. Я бы посоветовал вам создать две разные ячейки. Одно для текста с изображениями, а второе только для текста. Затем отмените в зависимости от данных, которые у вас есть в вашем источнике данных. Это значительно упростит вашу жизнь, и ваш cellForItem также станет чище.

2. @GaloTorresSevilla спасибо, я сделал это так, как вы сказали, но я подумал, может быть, это будет самый простой способ сделать это. Еще раз спасибо 🙂

3. На самом деле это самый простой способ. Это может показаться ненужным дополнительным кодированием, но на самом деле оно того стоит :). Удачи!

4. @GaloTorresSevilla, спасибо и тебе за информацию 🙂

Ответ №1:

вы не должны изменять высоту изображения на

 cell.image.heightAnchor.constraint(equalToConstant: 0).isActive = true

  

создайте новую переменную imageHeightConstraint в вас TimelinesPosts ,

установите эту переменную в setupViews()

imageHeightConstraint = image.heightAnchor.constraint(equalToConstant: ((UIScreen.main.bounds.width - 120) * 2) / 3).isActive = true

затем измените высоту на это

 // don't miss this code.
imageHeightConstraint.constant = ((UIScreen.main.bounds.width - 120) * 2) / 3
if types[indexPath.row] == 2 {
//***************     
} else if types[indexPath.row] == 3 {

//***************     

} else {
    imageHeightConstraint.constant = 0  
}
  

Комментарии:

1. Спасибо за ответ, @GaloTorresSevilla сказал «вы должны создавать разные ячейки для каждого типа, этот метод является наиболее чистым и простым способом». Итак, я создал новые ячейки, и теперь они работают хорошо. Еще раз спасибо 🙂

Ответ №2:

UIScrollView является родительским UICollectionView. Вы используете UIScrollView с UIScrollViewDelegate для настройки изображений с помощью va scrollOffset: CGFloat follow .y (ссылочный код)

 extension ViewController: UIScrollViewDelegate {
  func scrollViewDidScroll(_ scrollView: UIScrollView) {
    var scrollOffset : CGFloat = scrollView.contentOffset.y
    // process with scrollOffset
  }
}
  

Комментарии:

1. Спасибо за ответ, @GaloTorresSevilla сказал «вы должны создавать разные ячейки для каждого типа, этот метод является наиболее чистым и простым способом». Итак, я создал новые ячейки, и теперь они работают хорошо. Еще раз спасибо 🙂