各セルがビューのサイズで水平にスクロールするcollectionViewがあります。 collectionViewをページングするとき、セルごとにページングしません。セルは画面の中央にはありません。私はそれを修正するためにたくさんのことを試しましたが、運がありませんでした。問題のビデオは次のとおりです。 https://www.youtube.com/watch?v=tXsxWelk16w アイデアはありますか?
アイテム間のスペースを削除します。水平スクロールコレクションビューの場合、最小行間隔を0に設定します。これは、インターフェイスビルダーまたはUICollectionViewDelegateFlowLayout
プロトコルのメソッドを使用して実行できます。
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 0;
}
別の方法は、アイテム間の水平方向のスペースの値に対してセルの幅をcollectionViewの幅より小さくすることです。次に、項目間の水平スペースの半分に等しい左右のインセットを使用してセクションインセットを追加します。たとえば、最小行間隔は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);
}
3番目の方法:scrollViewDidEndDecelerating:
メソッドでcollectionViewスクロールを操作します。
- (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];
}
}
ここのデモSwift 3: https://github.com/damienromito/CollectionViewCustom
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
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 < 0 {
newPage = 0
}
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
}
Swift 4:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
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 < 0 {
newPage = 0
}
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
}
@ vlad-cheのSwiftバージョンは回答を受け入れました:
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)
}
}
行間隔を削除してセルを中央に保持するSwift 4ソリューション:
public func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
セルの間にスペースがあるcollectionView
フレームよりも小さいセルを使用できることにより、ユーザーに、どちらの側にもスクロールする他のセルがあることをユーザーに示唆できます。ただし、ページの中央揃えは期待どおりに機能しません。ユーザーがスクロールすると、各セルは徐々にオフセットが大きくなります。以下がうまく機能することがわかりました。各セルのセンタリング/スナップアニメーションは、collectionView
のスクロールが自然に終了する場所を微調整するだけなので、collectionView
をすばやく動かして別のindexPath
プロパティを十分に大きく設定して、セルが含まれるフレームのエッジに貼り付かないようにすることが重要です。また、セル間にスペースがあるため、ターゲットはsectionInset
をnilのindexPath
に着陸させ、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;
}
}
スイフト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)
}
}
}
Apple公式ガイドとサンプルコードから見たコード:
AssetViewController.Swift:
self.collectionView?.isPagingEnabled = true
self.collectionView?.frame = view.frame.insetBy(dx: -20.0, dy: 0.0)
同様の問題が発生した後、水平スクロールを使用する場合、デフォルトは垂直スクロールに設定されているため、高さは幅になり、幅は高さになります。値を切り替えてみて、それが役立つかどうかを確認してください。 https://developer.Apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
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