У меня есть UICollectionView
, в котором я показываю изображение или изображение видео с помощью кнопки воспроизведения. Ячейки занимают всю ширину экрана, поэтому на экране одновременно видна только одна ячейка. Пользователи могут прокручивать влево или вправо, чтобы показать следующее изображение или видео. Лучше всего сравнить его с новостями из Instagram.
Итак, пользователю всегда отображается изображение при прокрутке. Однако, когда я прокручиваю ячейки, когда есть, скажем, четыре или пять изображений, они смешиваются. Это мой код:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaSliderCell", for: indexPath) as! MediaSliderCell
if(dataArray.count > 0) {
if(dataArray[indexPath.item].mediaType == .photo) {
let mediaURL = URL(string: "https://myURL.com/media/\(dataArray[indexPath.item].mediaURL)")
cell.photoView.kf.setImage(with: mediaURL, options: [.targetCache(mediaCache)])
cell.photoView.isHidden = false
cell.videoView.isHidden = true
} else if(dataArray[indexPath.item].mediaType == .video) {
cell.photoView.isHidden = true
cell.videoView.isHidden = false
let mediaThumbURL = URL(string: "https://myURL.com/media/\(dataArray[indexPath.item].mediaThumbURL!)")
let mediaURL = URL(string: "https://myURL.com/media/\(dataArray[indexPath.item].mediaURL)")!
cell.videoView.placeholderView.kf.setImage(with: mediaThumbURL, options: [.targetCache(mediaCache)])
cell.videoView.mediaURL = mediaURL
cell.videoView.testLabel.text = "indexPath.item: \(indexPath.item)"
}
}
return cell
}
Я знаю, как работает снятие очереди. У меня были проблемы с этим в прошлом. Я также попробовал все, что я знаю до сих пор, чтобы избежать этой проблемы:
- установите для imageView.image значение nil в prepareForReuse ()
- , используйте оператор if else и установите imageView. image to nil в cellForItemAt, но это возвращает черный экран (поэтому тогда изображение отсутствует)
Это происходит, когда я использую видео. Что касается фотографии, я еще не видел этого, но это может быть и так. Как я могу это исправить?
Это мой MediaSliderCell
:
class MediaSliderCell: UICollectionViewCell {
override func prepareForReuse() {
videoView.placeholderView.kf.cancelDownloadTask()
videoView.placeholderView.image = UIImage()
photoView.image = UIImage()
}
var photoView: UIImageView = {
let photoView = UIImageView()
photoView.translatesAutoresizingMaskIntoConstraints = false
photoView.backgroundColor = .black
photoView.isHidden = true
return photoView
}()
var videoView: VideoView = {
let videoView = VideoView()
videoView.translatesAutoresizingMaskIntoConstraints = false
videoView.backgroundColor = .black
return videoView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func setupViews() {
addSubview(photoView)
addSubview(videoView)
photoView.topAnchor.constraint(equalTo: topAnchor).isActive = true
photoView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
photoView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
photoView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
videoView.topAnchor.constraint(equalTo: topAnchor).isActive = true
videoView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
videoView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
videoView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
VideoView
тоже пользовательский, но это просто реализация AVPlayer
и не долженвлиять на поведение клеток. Это довольно много кода, поэтому я не буду публиковать его, так как он не имеет отношения к отображаемым изображениям. Есть идеи, что здесь происходит? Когда я печатаю indexPaths и URL-адреса в cellForItemAt
, я всегда получаю правильный URL-адрес изображения, которое я должен увидеть . Но изображения перепутаны. Я использую KingFisher для загрузки изображений и кэширования их для будущего использования.
РЕДАКТИРОВАТЬ: В основном, насколько я понимаю ситуацию, в cellForItemAt
возвращаются правильные данные (по крайней мере, когда я их печатаю)вне). Я замечаю, что ячейки извлекаются всякий раз, когда iOS хочет получить их, поэтому iOS может извлекать данные для ячейки 0, затем ячейки 1, затем ячейки 2, затем снова ячейки 1 ... но это не должно быть проблемой.
Сначала я подумал, что проблема может быть в методе загрузки KingFisher, поскольку загрузка может закончиться позже, когда ячейка уже будет изменена. Но опять же, ячейка также использует неправильный mediaURL, поэтому не только изображение является неправильным, но также и mediaURL, на который я ссылаюсь (mediaURL, например, https://myURL.com/media/test.mp4, и mediaThumbURL, например, https://myURL.com/media/thumb/test.jpeg).Я думаю, что проблема кроется где-то еще, может быть, в VideoView? Может ли это быть повторно использовано или как-то неправильно связано?
Может быть также полезно упомянуть, что мой dataArray построен так:
struct MediaData: Codable {
var mediaType: MediaType // enum .photo or .video
var mediaURL: String
var mediaThumbURL: String?
}
Затем я просто добавляю все свои элементы, и поэтому мне нужно показать их в правильном порядке, поэтому я полагаюсь на indexPath.item, чтобы правильно выбрать их из массива.
EDIT2: теперь я замечаю, что возвращаемый indexPath иногда тоже неверен. Я добавил UILabel
в свою ячейку и добавил cell.testLabel.text = indexPath.item
. Иногда для первой ячейки (которая должна быть элементом indexPath 0) я получаю 3 какрезультат. Итак, самая первая ячейка, после прокрутки влево и вправо, затем имеет indexPath (0,3). Почему это так и как я могу это исправить?