[英]ios - UICollectionView change default offset when horizontal paging
[英]UICollectionView align logic missing in horizontal paging scrollview
我有一個UICollectionView
,它工作正常,直到我開始滾動。 這里有一些照片:
你可以看到它很棒。 當我開始滾動(啟用分頁)時,第一個在屏幕外顯示:
這就是問題。 原始我的視圖有3個視圖,我想滾動並僅顯示3個視圖。 但是當它滾動(啟用分頁)時,它隱藏了第一個視圖的一點點,並顯示下一頁的下一個第一個視圖的一點點。
這是一個視頻,因為它有點難以解釋: 問題的視頻(Dropbox)
這是我的UICollectionView
設置的圖片:
如果有人可以提供幫助,那將會很棒!
根本問題是Flow Layout不支持分頁。 要實現分頁效果,您必須犧牲單元格之間的空間。 並仔細計算單元格框架,並使其可以通過集合視圖框架進行划分而不會留下余地。 我會解釋原因。
說出以下布局就是你想要的。
請注意,最左邊距(綠色)不是單元格間距的一部分。 它由流動布局部分插入確定。 由於流布局不支持異構間距值。 這不是一項微不足道的任務。
因此,設置間距和插入后。 您將獲得以下布局。
滾動到下一頁后。 你的細胞顯然不符合你的預期。
使單元格間隔為0可以解決此問題。 但是,如果您希望頁面上有額外的邊距,則會限制您的設計,特別是如果邊距不同於單元格間距。 它還要求視圖幀必須可被單元格框整除。 有時,如果您的視圖框架未固定(考慮旋轉情況),則會很痛苦。
- (CGSize)collectionViewContentSize
{
// Only support single section for now.
// Only support Horizontal scroll
NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
numberOfItemsInSection:0];
CGSize canvasSize = self.collectionView.frame.size;
CGSize contentSize = canvasSize;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
{
NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount));
contentSize.width = page * canvasSize.width;
}
return contentSize;
}
- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize canvasSize = self.collectionView.frame.size;
NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f;
CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f;
NSUInteger page = indexPath.row / (rowCount * columnCount);
NSUInteger remainder = indexPath.row - page * (rowCount * columnCount);
NSUInteger row = remainder / columnCount;
NSUInteger column = remainder - row * columnCount;
CGRect cellFrame = CGRectZero;
cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing);
cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing);
cellFrame.size.width = self.itemSize.width;
cellFrame.size.height = self.itemSize.height;
if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
{
cellFrame.origin.x += page * canvasSize.width;
}
return cellFrame;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath];
attr.frame = [self frameForItemAtIndexPath:indexPath];
return attr;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
NSMutableArray * attrs = [NSMutableArray array];
[originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
NSIndexPath * idxPath = attr.indexPath;
CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
if (CGRectIntersectsRect(itemFrame, rect))
{
attr = [self layoutAttributesForItemAtIndexPath:idxPath];
[attrs addObject:attr];
}
}];
return attrs;
}
注意,上面的代碼片段只支持單節和水平滾動方向。 但它不難擴展。
此外,如果你沒有數百萬的細胞。 緩存那些UICollectionViewLayoutAttributes可能是一個好主意。
您可以在UICollectionView上禁用分頁,並使用自定義頁面寬度/偏移量實現自定義水平滾動/分頁機制,如下所示:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
float pageWidth = 210;
float currentOffset = scrollView.contentOffset.x;
float targetOffset = targetContentOffset->x;
float newTargetOffset = 0;
if (targetOffset > currentOffset)
newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
else
newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;
if (newTargetOffset < 0)
newTargetOffset = 0;
else if (newTargetOffset > scrollView.contentSize.width)
newTargetOffset = scrollView.contentSize.width;
targetContentOffset->x = currentOffset;
[scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}
這個答案是遲到的,但我剛剛一直在玩這個問題,發現漂移的原因是行間距 。 如果希望UICollectionView / FlowLayout以單元格寬度的精確倍數進行分頁,則必須設置:
UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
flowLayout.minimumLineSpacing = 0.0;
您不會認為行間距在水平滾動中起作用,但顯然它確實如此。
在我的情況下,我正在嘗試從左到右分頁,一次一個單元格,單元格之間沒有空格。 頁面的每一個轉彎都會從所需的位置引入一點點漂移,並且它似乎線性地累積。 每回合~10分 。 我意識到10.0是流布局中minimumLineSpacing的默認值。 當我將其設置為0.0時 ,沒有漂移,當我將其設置為邊界寬度的一半時,每個頁面都會移動額外的一半邊界。
更改minimumInteritemSpacing 無效 。
編輯 - 從UICollectionViewFlowLayout的文檔:
@property(nonatomic)CGFloat minimumLineSpacing;
討論
...
對於垂直滾動網格,此值表示連續行之間的最小間距。 對於水平滾動網格,此值表示連續列之間的最小間距。 此間距不應用於標題和第一行之間或最后一行和頁腳之間的空格。
此屬性的默認值為10.0。
以下文章的解決方案優雅而簡單。 主要思想是在collectionView的頂部創建scrollView並傳遞所有contentOffset值。
http://b2cloud.com.au/tutorial/uiscrollview-paging-size/
應該通過實現這個方法來說:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
我沒有像使用pagingEnabled = YES那樣實現平滑動畫。
我知道這個問題已經過時了,但對於碰巧偶然發現這個問題的人來說。
要糾正此問題,您需要將MinimumInterItemSpacing設置為0並減少內容的幀。
我想我明白了這個問題。 我會嘗試讓你理解它。
如果你仔細觀察,那么你會看到這個問題只是逐漸發生,而不僅僅是在第一頁滑動。
如果我理解正確,在您的應用程序中,目前,每個UICollectionView項目都是我們看到的那些圓角框,並且您在所有這些項目之間有一些不變的偏移/邊距。 這就是造成這個問題的原因。
相反,你應該做的是創建一個UICollectionView項,它是整個視圖寬度的1/3,然后在其中添加該圓形圖像視圖。 要引用圖像,綠色應該是您的UICollectionViewItem而不是黑色。
你推出自己的UICollectionViewFlowLayout
嗎?
如果是這樣,添加-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
將幫助您計算scrollview應停止的位置。
這可能有用(NB:UNTESTED!):
-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
withScrollingVelocity:(CGPoint)velocity
{
CGFloat offsetAdjustment = MAXFLOAT;
CGFloat targetX = proposedContentOffset.x + self.minimumInteritemSpacing + self.sectionInset.left;
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
for(UICollectionViewLayoutAttributes *layoutAttributes in array) {
if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
CGFloat itemX = layoutAttributes.frame.origin.x;
if (ABS(itemX - targetX) < ABS(offsetAdjustment)) {
offsetAdjustment = itemX - targetX;
}
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
我的答案基於答案https://stackoverflow.com/a/27242179/440168,但更簡單。
您應該將UIScrollView
放在UICollectionView
上方並給它們相同的大小:
@property (nonatomic, weak) IBOutlet UICollectionView *collectionView;
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
然后配置集合視圖的contentInset
,例如:
CGFloat inset = self.view.bounds.size.width*2/9;
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);
和滾動視圖的contentSize
:
self.scrollView.contentSize = CGSizeMake(self.placesCollectionView.bounds.size.width*[self.collectionView numberOfItemsInSection:0],0);
不要忘記設置滾動視圖的委托:
self.scrollView.delegate = self;
並實現主要魔力:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.scrollView) {
CGFloat inset = self.view.bounds.size.width*2/9;
CGFloat scale = (self.placesCollectionView.bounds.size.width-2*inset)/scrollView.bounds.size.width;
self.collectionView.contentOffset = CGPointMake(scrollView.contentOffset.x*scale - inset, 0);
}
}
你的UICollectionView
的寬度應該是單元格大小+左右插圖的精確乘法。 在您的示例中,如果單元格寬度為96,則UICollectionView
的寬度應為(96 + 5 + 5) * 3 = 318
。 或者,如果您希望保持UICollectionView的320寬度,則單元格大小寬度應為320 / 3 - 5 - 5 = 96.666
。
如果這沒有幫助,那么當應用程序運行時,您的UICollectionView
的寬度可能與xib文件中設置的寬度不同。 要檢查這一點 - 添加NSLog
語句以在運行時打印視圖的大小:
NSLog(@"%@", NSStringFromCGRect(uiContentViewController.view.frame));
這是我遇到的同樣問題,我在另一篇文章上發布了我的解決方案,所以我會在這里再次發布。
我找到了一個解決方案,它涉及子類化UICollectionViewFlowLayout。
我的CollectionViewCell大小為302 X 457,我將最小行間距設置為18(每個單元格為9pix)
當您從該類擴展時,有一些方法需要被覆蓋。 其中之一是
在這個方法中,我需要加上UICollectionView中的總寬度。 這包括([datasource count] * widthOfCollectionViewCell)+([datasource count] * 18)
這是我的自定義UICollectionViewFlowLayout方法....
-(id)init
{
if((self = [super init])){
self.itemSize = CGSizeMake(302, 457);
self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.minimumInteritemSpacing = 0.0f;
self.minimumLineSpacing = 18.0f;
[self setScrollDirection:UICollectionViewScrollDirectionHorizontal];
}
return self;
}
-(CGSize)collectionViewContentSize{
return CGSizeMake((numCellsCount * 302)+(numCellsCount * 18), 457);
}
這對我有用,所以我希望別人覺得它很有用!
您還可以將視圖寬度設置為“320 +間距”,然后將頁面啟用設置為yes。 每次都會滾動'320 +間距'。 我認為這是因為頁面啟用會滾動視圖的寬度而不是屏幕的寬度。
我想我確實有這個問題的解決方案。 但如果它是最好的,我不會。
UICollectionViewFlowLayout
確實包含一個名為sectionInset
的屬性。 因此,您可以將“插入”部分設置為您需要的任何內容,並使1頁等於一個部分。 因此,您的滾動應自動適合頁面(=部分)
我在分頁方面遇到了類似的問題。 即使單元格插入全部為0並且單元格的寬度和高度與UICollectionView
大小UICollectionView
,但分頁不正確。
我注意到像一個錯誤的聲音在這個版本( UICollectionView
,iOS 6中):我可以看到,如果我有工作UICollectionView
與寬度= 310px以上,高度= 538px,我遇到了麻煩。 但是,如果我將寬度減小到300px(相同的高度),我的工作就完美了!
對於將來的參考,我希望它有所幫助!
當嘗試在具有分段插入和單元格和行間距的3 x 3網格單元上進行水平分頁時,我遇到了類似的問題。
對我來說(在嘗試了許多建議 - 包括子類化UICollectionViewFlowLayout和各種UIScrollView委托解決方案之后)的答案很簡單。 我只是使用UICollectionView中的部分,將我的數據集分成9個項目(或更少)的部分,並使用numberOfSectionsInCollectionView和numberOfItemsInSection UICollectionView數據源方法。
UICollectionView的水平分頁現在可以很好地工作。 我推薦這種方法給目前在類似情況下撕掉頭發的人。
如果您正在為UICollectionView使用默認的流布局,並且不希望每個單元格之間有任何空格,則可以通過以下方式將其miniumumLineSpacing屬性設置為0:
((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).minimumLineSpacing = 0;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.