Anonymous
Как исправить зависание прокрутки просмотра коллекции?
Сообщение
Anonymous » 24 дек 2024, 18:15
Я использую этот код, чтобы показать ход загрузки файла в ячейках представления моей коллекции. Все работает нормально. А если я не загружаю файл, я могу легко прокручивать представление коллекции, коснувшись ячейки представления коллекции. Но когда я закрываю файл, у меня возникают проблемы с прокруткой. Если я касаюсь ячейки коллекций, мое представление прокрутки не прокручивается.
мой код:
Код: Выделить всё
import UIKit
enum DownloadStatus {
case none
case inProgress
case completed
case failed
}
struct item {
var number: Int!
var downloadStatus: DownloadStatus = .none
var progress: Float = 0.0
init(number: Int) { self.number = number }
}
var downloadQueue = [Int: [Int]]()
var masterIndex = 0
extension URLSession {
func getSessionDescription () -> Int { return Int(self.sessionDescription!)! } // Item ID
func getDebugDescription () -> Int { return Int(self.debugDescription)! } // Collection ID
}
class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {
static var shared = DownloadManager()
var identifier : Int = -1
var collectionId : Int = -1
var folderPath : String = ""
typealias ProgressHandler = (Int, Int, Float) -> ()
var onProgress : ProgressHandler? {
didSet { if onProgress != nil { let _ = activate() } }
}
var onSuccess: ((Int) -> Void)? // Void)? // URLSession {
let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background.\(NSUUID.init())")
let urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
urlSession.sessionDescription = String(identifier)
urlSession.accessibilityHint = String(collectionId)
return urlSession
}
private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Int, Float) -> ()) {
session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
let progress = downloads.map({ (task) -> Float in
if task.countOfBytesExpectedToReceive > 0 {
return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
} else {
return 0.0
}
})
completionHandler(session.getSessionDescription(), Int(session.accessibilityHint!)!, progress.reduce(0.0, +))
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
let stringNumb = (session.accessibilityHint ?? "hit")
let someNumb = Int(stringNumb as String)
let string1 = (session.sessionDescription ?? "hit")
let some1 = Int(string1 as String)
if let idx = downloadQueue[someNumb!]?.firstIndex(of: some1!) {
downloadQueue[someNumb!]?.remove(at: idx)
print("remove:: did finish :: \(downloadQueue)")
}
onSuccess?(collectionId) // call when download success
let fileName = downloadTask.originalRequest?.url?.lastPathComponent
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(folderPath)"))
do {
try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil)
destinationURLForFile.appendPathComponent(String(describing: fileName!))
try fileManager.moveItem(at: location, to: destinationURLForFile)
} catch (let error) {
print(error)
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if totalBytesExpectedToWrite > 0 {
if let onProgress = onProgress {
calculateProgress(session: session, completionHandler: onProgress)
}
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
let stringNumb = (session.accessibilityHint ?? "hit")
let someNumb = Int(stringNumb as String)
let string1 = (session.sessionDescription ?? "hit")
let some1 = Int(string1 as String)
onError?(error, collectionId) // call when download error
if let idx = downloadQueue[someNumb!]?.firstIndex(of: some1!) {
downloadQueue[someNumb!]?.remove(at: idx)
print("remove when complete:\(downloadQueue)")
}
}
}
public struct Item: Decodable, Hashable {
let index: Int
let title: String
let image: String
let backgroundColor: String
let borderColor: String
}
public struct Section: Decodable, Hashable {
let index: Int
let identifier: String
let title: String
let subtitle: String
let item: [Item]
}
class CollectionController: UIViewController, UICollectionViewDelegate {
typealias ProgressHandler = (Int, Float) -> ()
var onProgress : ProgressHandler?
var items = [item]()
var collectionView: UICollectionView!
var dataSource: UICollectionViewDiffableDataSource?
let sections: [Section] = [.init(index: 0, identifier: "carouselCell", title: "title", subtitle: "sub", item: [
Item(index: 0, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 1, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 2, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 3, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 4, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 5, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 6, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 7, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 8, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 9, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 10, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 11, title: "Hello", image: "", backgroundColor: "", borderColor: ""),
Item(index: 12, title: "Hello", image: "", backgroundColor: "", borderColor: "")
])]
override func viewDidLoad() {
super.viewDidLoad()
createCollectionView()
setupScrollView()
let count = dataSource!.snapshot().numberOfItems
for index in 0...count {
items.append(item(number: index))
}
}
func setupScrollView() {
collectionView.collectionViewLayout = createCompositionalLayout()
collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: false)
}
func createDataSource() {
dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, item in
guard let self = self else { return UICollectionViewCell() }
switch self.sections[indexPath.section].identifier {
case "carouselCell":
let cell = self.configure(CarouselCell.self, with: item, for: indexPath)
if indexPath.row < self.items.count { // T {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { fatalError(" — \(cellType)") }
cell.configure(with: item)
return cell
}
func reloadData() {
var snapshot = NSDiffableDataSourceSnapshot()
snapshot.appendSections(sections)
for section in sections { snapshot.appendItems(section.item, toSection: section) }
dataSource?.apply(snapshot)
}
func createCollectionView() {
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createCompositionalLayout())
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.delegate = self
collectionView.contentInsetAdjustmentBehavior = .never
view.addSubview(collectionView)
collectionView.register(CarouselCell.self, forCellWithReuseIdentifier: CarouselCell.reuseIdentifier)
createDataSource()
reloadData()
}
func createCompositionalLayout() -> UICollectionViewLayout {
UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupWidth = (layoutEnvironment.container.contentSize.width * 1.05)/3
let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(groupWidth), heightDimension: .absolute(groupWidth))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: (layoutEnvironment.container.contentSize.height/2) - (groupWidth/2), leading: 0, bottom: 0, trailing: 0)
section.interGroupSpacing = 20
section.orthogonalScrollingBehavior = .groupPagingCentered
return section
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let directory: String = path[0]
var queueArray = downloadQueue[indexPath.row+1] ?? [Int]()
queueArray.append(indexPath.row+1)
downloadQueue[indexPath.row+1] = queueArray
let url = URL(string: "https://file-examples.com/storage/fec85039006734629a992d7/2017/04/file_example_MP4_640_3MG.mp4")!
let downloadManager = DownloadManager()
downloadManager.identifier = indexPath.row+1
downloadManager.collectionId = indexPath.row+1
downloadManager.folderPath = "\(indexPath.row+1)"
let downloadTaskLocal = downloadManager.activate().downloadTask(with: url)
downloadTaskLocal.resume()
//var item = items[indexPath.row]
Подробнее здесь: [url]https://stackoverflow.com/questions/79239405/how-to-fix-collection-view-scrolling-freezes[/url]
1735053306
Anonymous
Я использую этот код, чтобы показать ход загрузки файла в ячейках представления моей коллекции. Все работает нормально. А если я не загружаю файл, я могу легко прокручивать представление коллекции, коснувшись ячейки представления коллекции. Но когда я закрываю файл, у меня возникают проблемы с прокруткой. Если я касаюсь ячейки коллекций, мое представление прокрутки не прокручивается. мой код: [code]import UIKit enum DownloadStatus { case none case inProgress case completed case failed } struct item { var number: Int! var downloadStatus: DownloadStatus = .none var progress: Float = 0.0 init(number: Int) { self.number = number } } var downloadQueue = [Int: [Int]]() var masterIndex = 0 extension URLSession { func getSessionDescription () -> Int { return Int(self.sessionDescription!)! } // Item ID func getDebugDescription () -> Int { return Int(self.debugDescription)! } // Collection ID } class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate { static var shared = DownloadManager() var identifier : Int = -1 var collectionId : Int = -1 var folderPath : String = "" typealias ProgressHandler = (Int, Int, Float) -> () var onProgress : ProgressHandler? { didSet { if onProgress != nil { let _ = activate() } } } var onSuccess: ((Int) -> Void)? // Void)? // URLSession { let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background.\(NSUUID.init())") let urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) urlSession.sessionDescription = String(identifier) urlSession.accessibilityHint = String(collectionId) return urlSession } private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Int, Float) -> ()) { session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in let progress = downloads.map({ (task) -> Float in if task.countOfBytesExpectedToReceive > 0 { return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive) } else { return 0.0 } }) completionHandler(session.getSessionDescription(), Int(session.accessibilityHint!)!, progress.reduce(0.0, +)) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){ let stringNumb = (session.accessibilityHint ?? "hit") let someNumb = Int(stringNumb as String) let string1 = (session.sessionDescription ?? "hit") let some1 = Int(string1 as String) if let idx = downloadQueue[someNumb!]?.firstIndex(of: some1!) { downloadQueue[someNumb!]?.remove(at: idx) print("remove:: did finish :: \(downloadQueue)") } onSuccess?(collectionId) // call when download success let fileName = downloadTask.originalRequest?.url?.lastPathComponent let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let documentDirectoryPath:String = path[0] let fileManager = FileManager() var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(folderPath)")) do { try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil) destinationURLForFile.appendPathComponent(String(describing: fileName!)) try fileManager.moveItem(at: location, to: destinationURLForFile) } catch (let error) { print(error) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { if totalBytesExpectedToWrite > 0 { if let onProgress = onProgress { calculateProgress(session: session, completionHandler: onProgress) } } } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { let stringNumb = (session.accessibilityHint ?? "hit") let someNumb = Int(stringNumb as String) let string1 = (session.sessionDescription ?? "hit") let some1 = Int(string1 as String) onError?(error, collectionId) // call when download error if let idx = downloadQueue[someNumb!]?.firstIndex(of: some1!) { downloadQueue[someNumb!]?.remove(at: idx) print("remove when complete:\(downloadQueue)") } } } public struct Item: Decodable, Hashable { let index: Int let title: String let image: String let backgroundColor: String let borderColor: String } public struct Section: Decodable, Hashable { let index: Int let identifier: String let title: String let subtitle: String let item: [Item] } class CollectionController: UIViewController, UICollectionViewDelegate { typealias ProgressHandler = (Int, Float) -> () var onProgress : ProgressHandler? var items = [item]() var collectionView: UICollectionView! var dataSource: UICollectionViewDiffableDataSource? let sections: [Section] = [.init(index: 0, identifier: "carouselCell", title: "title", subtitle: "sub", item: [ Item(index: 0, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 1, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 2, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 3, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 4, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 5, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 6, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 7, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 8, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 9, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 10, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 11, title: "Hello", image: "", backgroundColor: "", borderColor: ""), Item(index: 12, title: "Hello", image: "", backgroundColor: "", borderColor: "") ])] override func viewDidLoad() { super.viewDidLoad() createCollectionView() setupScrollView() let count = dataSource!.snapshot().numberOfItems for index in 0...count { items.append(item(number: index)) } } func setupScrollView() { collectionView.collectionViewLayout = createCompositionalLayout() collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: false) } func createDataSource() { dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, item in guard let self = self else { return UICollectionViewCell() } switch self.sections[indexPath.section].identifier { case "carouselCell": let cell = self.configure(CarouselCell.self, with: item, for: indexPath) if indexPath.row < self.items.count { // T { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { fatalError(" — \(cellType)") } cell.configure(with: item) return cell } func reloadData() { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections(sections) for section in sections { snapshot.appendItems(section.item, toSection: section) } dataSource?.apply(snapshot) } func createCollectionView() { collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createCompositionalLayout()) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] collectionView.delegate = self collectionView.contentInsetAdjustmentBehavior = .never view.addSubview(collectionView) collectionView.register(CarouselCell.self, forCellWithReuseIdentifier: CarouselCell.reuseIdentifier) createDataSource() reloadData() } func createCompositionalLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupWidth = (layoutEnvironment.container.contentSize.width * 1.05)/3 let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(groupWidth), heightDimension: .absolute(groupWidth)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: (layoutEnvironment.container.contentSize.height/2) - (groupWidth/2), leading: 0, bottom: 0, trailing: 0) section.interGroupSpacing = 20 section.orthogonalScrollingBehavior = .groupPagingCentered return section } } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let directory: String = path[0] var queueArray = downloadQueue[indexPath.row+1] ?? [Int]() queueArray.append(indexPath.row+1) downloadQueue[indexPath.row+1] = queueArray let url = URL(string: "https://file-examples.com/storage/fec85039006734629a992d7/2017/04/file_example_MP4_640_3MG.mp4")! let downloadManager = DownloadManager() downloadManager.identifier = indexPath.row+1 downloadManager.collectionId = indexPath.row+1 downloadManager.folderPath = "\(indexPath.row+1)" let downloadTaskLocal = downloadManager.activate().downloadTask(with: url) downloadTaskLocal.resume() //var item = items[indexPath.row] Подробнее здесь: [url]https://stackoverflow.com/questions/79239405/how-to-fix-collection-view-scrolling-freezes[/url]