У меня есть горизонтальная прокрутка collectionView с каждой ячейкой размером с представлением. Когда я просматриваю через collectionView, он не разбивается по ячейкам. Ячейки не находятся в центре экрана. Я попробовал кучу вещей, чтобы попытаться исправить это и не повезло. Вот видео проблемы: https://www.youtube.com/watch?v=tXsxWelk16w Любые идеи?
UICollectionView Горизонтальный пейджинг не центрирован
Ответ 1
Удалите пробелы между элементами. Для горизонтального представления коллекции прокрутки установите минимальное расстояние между строками до 0. Вы можете сделать это с помощью построителя интерфейса или с помощью метода UICollectionViewDelegateFlowLayout
:
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 0;
}
Другой способ заключается в том, что ширина вашей ячейки меньше ширины коллекцииView для значения горизонтального пространства между элементами. Затем добавьте секционные вставки с левой и правой вставками, равными половине горизонтального пространства между элементами. Например, минимальное расстояние между линиями равно 10:
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(collectionView.frame.size.width - 10, collectionView.frame.size.height);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 5, 0, 5);
}
И третий способ: манипулировать collectionView прокруткой в scrollViewDidEndDecelerating:
:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (scrollView == self.collectionView) {
CGPoint currentCellOffset = self.collectionView.contentOffset;
currentCellOffset.x += self.collectionView.frame.size.width / 2;
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:currentCellOffset];
[self.collectionView scrollToItemAtIndexPath:indexPath
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
}
}
Ответ 2
Демо здесь в Swift 3: https://github.com/damienromito/CollectionViewCustom
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { let pageWidth = Float(itemWidth + itemSpacing) let targetXContentOffset = Float(targetContentOffset.pointee.x) let contentWidth = Float(collectionView!.contentSize.width ) var newPage = Float(self.pageControl.currentPage) if velocity.x == 0 { newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0 } else { newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1) if newPage contentWidth / pageWidth) { newPage = ceil(contentWidth / pageWidth) - 1.0 } } self.pageControl.currentPage = Int(newPage) let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y) targetContentOffset.pointee = point }
Ответ 3
Возможность иметь ячейки меньшего размера collectionView
с пространством между ячейками позволяет намекнуть пользователю, что есть другие ячейки с обеих сторон для прокрутки, что является большой победой для UX. Но для центрирования страниц не работает должным образом, поскольку каждая ячейка постепенно становится более смещенной по мере прокрутки пользователя. Я нашел следующее, чтобы хорошо работать. Анимация центрирования/привязки в каждой ячейке почти невидима для пользователя, поскольку она только настраивается, где прокрутка collectionView
заканчивается естественным образом, а не подталкивает collectionView
, чтобы быстро перейти к другому indexPath
. По-прежнему важно иметь свойство sectionInset
, установленное достаточно большим, чтобы позволить ячейке не прилипать к содержащим рамкам кадра. Кроме того, поскольку между ячейками есть пробелы, цель может приземляться на indexPath
nil, что приведет к тому, что collectionView
будет прокручиваться назад до начала. Я немного исправил это смещение, а затем снова попытался, но здесь можно было бы использовать разные подходы.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
//Ensure the scrollview is the collectionview we care about
if (scrollView == self.collectionView) {
// Find cell closest to the frame centre with reference from the targetContentOffset.
CGPoint frameCentre = self.collectionView.center;
CGPoint targetOffsetToCentre = CGPointMake((* targetContentOffset).x + frameCentre.x, (* targetContentOffset).y + frameCentre.y);
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:targetOffsetToCentre];
//Check for "edgecase" that the target will land between cells and then find a close neighbour to prevent scrolling to index {0,0}.
while (!indexPath) {
targetOffsetToCentre.x += ((UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout).minimumInteritemSpacing;
indexPath = [self.collectionView indexPathForItemAtPoint:targetOffsetToCentre];
}
// Find the centre of the target cell
CGPoint centreCellPoint = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath].center;
// Calculate the desired scrollview offset with reference to desired target cell centre.
CGPoint desiredOffset = CGPointMake(centreCellPoint.x - frameCentre.x, centreCellPoint.y - frameCentre.y);
*targetContentOffset = desiredOffset;
}
}
Ответ 4
Swift 3
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView == self.collectionView {
var currentCellOffset = self.collectionView.contentOffset
currentCellOffset.x += self.collectionView.frame.width / 2
if let indexPath = self.collectionView.indexPathForItem(at: currentCellOffset) {
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
}
Ответ 5
Быстрая версия ответа @vlad-che:
extension GoodsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let frameSize = collectionView.frame.size
return CGSize(width: frameSize.width - 10, height: frameSize.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
}
}
Ответ 6
Swift 3.0 устанавливает собственный UICollectionViewFlowLayout
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = UIScreen.main.bounds.width
layout.itemSize = CGSize(width: width, height: 154)
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
collectionView?.collectionViewLayout = layout
Ответ 7
После подобной проблемы я исправил свою проблему, поняв, что при использовании горизонтальной прокрутки высота теперь равна ширине, а ширина теперь является высотой, поскольку по умолчанию устанавливается вертикальная прокрутка. Попробуйте переключить значения и посмотрите, поможет ли это. https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
Ответ 8
Код, который я только что видел из официальных руководств Apple и пример кода:
AssetViewController.swift:
self.collectionView?.isPagingEnabled = true
self.collectionView?.frame = view.frame.insetBy(dx: -20.0, dy: 0.0)
Ответ 9
Решение Swift 3, основанное на ответе @Santos, для использования, если у вас есть обычный горизонтальный просмотр подкачки, без контроля страницы, как это делал Паоло в своем примере Swift 3.
Я использовал это, чтобы решить проблему, когда полноэкранные ячейки с горизонтальной пейджинговой ячейкой с пользовательским аниматором UICollectionViewFlowLayout не завершили поворот И закончили смещение, так что края рамки с полным экраном были все более горизонтально отключены от когда вы прокручиваете (например, в видеоролике OP).
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Ensure the scrollview is the one on the collectionView we care are working with
if (scrollView == self.collectionView) {
// Find cell closest to the frame centre with reference from the targetContentOffset.
let frameCenter: CGPoint = self.collectionView.center
var targetOffsetToCenter: CGPoint = CGPoint(x: targetContentOffset.pointee.x + frameCenter.x, y: targetContentOffset.pointee.y + frameCenter.y)
var indexPath: IndexPath? = self.collectionView.indexPathForItem(at: targetOffsetToCenter)
// Check for "edge case" where the target will land right between cells and then next neighbor to prevent scrolling to index {0,0}.
while indexPath == nil {
targetOffsetToCenter.x += 10
indexPath = self.collectionView.indexPathForItem(at: targetOffsetToCenter)
}
// safe unwrap to make sure we found a valid index path
if let index = indexPath {
// Find the centre of the target cell
if let centerCellPoint: CGPoint = collectionView.layoutAttributesForItem(at: index)?.center {
// Calculate the desired scrollview offset with reference to desired target cell centre.
let desiredOffset: CGPoint = CGPoint(x: centerCellPoint.x - frameCenter.x, y: centerCellPoint.y - frameCenter.y)
targetContentOffset.pointee = desiredOffset
}
}
}
}