У меня есть горизонтально прокручивать uicollectionView < /code> in swift.
Inside ScrollViewDidsCroll < /code>, я применяю вращение и масштаб преобразования в видимые ячейки для создания эффекта наклона карты. < /p> Проблема: < /strong>
Если я дважды используется в коллекции. «Замороженный»-он перестает реагировать на жесты смахивания, и центрированная ячейка остается застрявшей на месте, пока я не перезагружаю данные. Эффект преобразования и предотвращает замораживание сбора после мультитахового или двойного табара?
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? UICollectionView else { return }
for cell in collectionView.visibleCells {
// 1. Calculate the cell's horizontal distance from the center of the screen
let centerX = view.bounds.width / 2
let cellCenter = collectionView.convert(cell.center, to: view)
let distance = centerX - cellCenter.x
// 2. Calculate rotation and scale based on this distance
// The further from the center, the more it rotates and shrinks.
let maxDistance = collectionView.bounds.width / 2
let normalizedDistance = distance / maxDistance // Value from -1 to 1
let maxAngle = CGFloat.pi / 30 // A subtle angle (e.g., 6 degrees)
let angle = maxAngle * normalizedDistance
let minScale: CGFloat = 0.9
let scale = 1.0 - (abs(normalizedDistance) * (1.0 - minScale))
// 3. Apply the transform
UIView.animate(withDuration: 0.3, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
cell.transform = CGAffineTransform(rotationAngle: angle).scaledBy(x: scale, y: scale)
}, completion: nil)
}
// ✅ Set initial centered index once after layout pass
if !hasSetInitialCenteredIndex {
hasSetInitialCenteredIndex = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
self.snapToNearestCell()
self.applyTransformToVisibleCells()
}
}
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.cardsCollectionView.isUserInteractionEnabled = false
isScrolling = true
let velocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
currentScrollDirection = velocity.x == 0 ? 0 : (velocity.x > 0 ? 1 : -1)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.cardsCollectionView.isUserInteractionEnabled = true
isScrolling = false
let pageWidth = scrollView.frame.size.width
let currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
if currentPage == 0 {
let indexPath = IndexPath(item: infinitePlaceholderArray.count - 2, section: 0)
cardsCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
// Delay snapping until layout is corrected
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.snapToNearestCell()
UIView.animate(withDuration: 0.3) {
self.applyTransformToVisibleCells()
}
}
return
} else if currentPage == infinitePlaceholderArray.count - 1 {
let indexPath = IndexPath(item: 1, section: 0)
cardsCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false)
// Delay snapping
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.snapToNearestCell()
UIView.animate(withDuration: 0.3) {
self.applyTransformToVisibleCells()
}
}
return
}
// No wrapping, snap normally
snapToNearestCell()
UIView.animate(withDuration: 0.3) {
self.applyTransformToVisibleCells()
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.cardsCollectionView.isUserInteractionEnabled = true
isScrolling = false
snapToNearestCell()
UIView.animate(withDuration: 0.3) {
self.applyTransformToVisibleCells()
}
}
}
func setupInfiniteDataSource() {
// Make sure you have data to work with
guard !placeholderArray.isEmpty else { return }
// [Last Item] + [All Original Items] + [First Item]
infinitePlaceholderArray.append(placeholderArray.last!)
infinitePlaceholderArray.append(contentsOf: placeholderArray)
infinitePlaceholderArray.append(placeholderArray.first!)
}
func applyTransformToVisibleCells() {
guard let collectionView = cardsCollectionView else { return }
for cell in collectionView.visibleCells {
let centerX = view.bounds.width / 2
let cellCenter = collectionView.convert(cell.center, to: view)
let distance = centerX - cellCenter.x
let maxDistance = collectionView.bounds.width / 2
let normalizedDistance = distance / maxDistance
let maxAngle = CGFloat.pi / 30
let angle = maxAngle * normalizedDistance
let minScale: CGFloat = 0.9
let scale = 1.0 - (abs(normalizedDistance) * (1.0 - minScale))
cell.transform = CGAffineTransform(rotationAngle: angle).scaledBy(x: scale, y: scale)
}
}
private func snapToNearestCell() {
guard let collectionView = cardsCollectionView else { return }
let centerX = collectionView.bounds.size.width / 2 + collectionView.contentOffset.x
var closestIndexPath: IndexPath?
var closestDistance: CGFloat = .greatestFiniteMagnitude
for cell in collectionView.visibleCells {
let cellCenterX = cell.center.x
let distance = abs(cellCenterX - centerX)
if distance < closestDistance {
closestDistance = distance
closestIndexPath = collectionView.indexPath(for: cell)
}
}
if let indexPath = closestIndexPath {
currentlyCenteredIndexPath = indexPath // Track centered cell
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
private func handleInfiniteScrollWrapping(for scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let currentPage = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
if currentPage == 0 {
let targetIndexPath = IndexPath(item: infinitePlaceholderArray.count - 2, section: 0)
cardsCollectionView.scrollToItem(at: targetIndexPath, at: .centeredHorizontally, animated: false)
} else if currentPage == infinitePlaceholderArray.count - 1 {
let targetIndexPath = IndexPath(item: 1, section: 0)
cardsCollectionView.scrollToItem(at: targetIndexPath, at: .centeredHorizontally, animated: false)
}
}
}
я попробовал: [/b]
[*] Обнаружение нескольких прикосновений в Touchesbegan и вызов my snaptonearestcell () для принудительного снимка. Просмотреть во время анимации SNAP.
ScrollviewWillendDragging и ScrollViewDidEdDecelerating для запуска вручную после мульти-Touch. Вид сбора должен прийти к ближайшей ячейке после мульти-навязчивого события и оставаться прокручиваемым как обычно. Прокрутка прекращает работу полностью, и мне нужно перезагрузить представление сбора, чтобы восстановить взаимодействие.
У меня есть горизонтально прокручивать uicollectionView < /code> in swift. Inside ScrollViewDidsCroll < /code>, я применяю вращение и масштаб преобразования в видимые ячейки для создания эффекта наклона карты. < /p> [b] Проблема: < /strong>
Если я дважды используется в коллекции. «Замороженный»-он перестает реагировать на жесты смахивания, и центрированная ячейка остается застрявшей на месте, пока я не перезагружаю данные. Эффект преобразования и предотвращает замораживание сбора после мультитахового или двойного табара?[code]func scrollViewDidScroll(_ scrollView: UIScrollView) { guard let collectionView = scrollView as? UICollectionView else { return }
for cell in collectionView.visibleCells { // 1. Calculate the cell's horizontal distance from the center of the screen let centerX = view.bounds.width / 2 let cellCenter = collectionView.convert(cell.center, to: view) let distance = centerX - cellCenter.x
// 2. Calculate rotation and scale based on this distance // The further from the center, the more it rotates and shrinks. let maxDistance = collectionView.bounds.width / 2 let normalizedDistance = distance / maxDistance // Value from -1 to 1
let maxAngle = CGFloat.pi / 30 // A subtle angle (e.g., 6 degrees) let angle = maxAngle * normalizedDistance
let minScale: CGFloat = 0.9 let scale = 1.0 - (abs(normalizedDistance) * (1.0 - minScale))
for cell in collectionView.visibleCells { let centerX = view.bounds.width / 2 let cellCenter = collectionView.convert(cell.center, to: view) let distance = centerX - cellCenter.x
let maxDistance = collectionView.bounds.width / 2 let normalizedDistance = distance / maxDistance
let maxAngle = CGFloat.pi / 30 let angle = maxAngle * normalizedDistance
let minScale: CGFloat = 0.9 let scale = 1.0 - (abs(normalizedDistance) * (1.0 - minScale))
if currentPage == 0 { let targetIndexPath = IndexPath(item: infinitePlaceholderArray.count - 2, section: 0) cardsCollectionView.scrollToItem(at: targetIndexPath, at: .centeredHorizontally, animated: false) } else if currentPage == infinitePlaceholderArray.count - 1 { let targetIndexPath = IndexPath(item: 1, section: 0) cardsCollectionView.scrollToItem(at: targetIndexPath, at: .centeredHorizontally, animated: false) } } } [/code] я попробовал: [/b]
[*] Обнаружение нескольких прикосновений в Touchesbegan и вызов my snaptonearestcell () для принудительного снимка. Просмотреть во время анимации SNAP.
ScrollviewWillendDragging и ScrollViewDidEdDecelerating для запуска вручную после мульти-Touch. Вид сбора должен прийти к ближайшей ячейке после мульти-навязчивого события и оставаться прокручиваемым как обычно. Прокрутка прекращает работу полностью, и мне нужно перезагрузить представление сбора, чтобы восстановить взаимодействие.