- 一:監聽滾動中止的時刻
- 2、監聽reloadData刷新列表完畢的時機
- 3、自由拖拽
- 4、瀑布流
- 5、浮動的Header
scrollToRow
中止setContentOffset
中止self.tableView.setContentOffset(CGPoint.init(x: 0, y: 0), animated: false)
print("執行這行代碼的時候,已經滾動完畢")
複製代碼
詳情參考:監聽reloadData刷新列表完畢的時機git
layoutIfNeeded
方法,強制重繪並等待完成。reloadData
方法會在主線程執行,經過GCD
,使後續操做排隊在reloadData
後面執行。一次runloop
有兩個機會執行GCD dispatch main queue
中的任務,分別在休眠前和被喚醒後。設置listView
的layoutIfNeeded
爲YES,在即將進入休眠時執行異步任務,重繪一次界面。UICollectionView
、UITableView
,layoutSubviews
以後看成reloadData
完成(複雜,但能夠更好的理解方法一)
- 第一步 :給
UICollectionviewCell
添加一個長按手勢UILongPressGestureRecognizer
,經過代理傳遞到UIViewController
中。- 第二步 :開始長按時(
UIGestureRecognizerStateBegan
)對cell
進行截圖而且隱藏cell
。- 第三步 :移動時(
UIGestureRecognizerStateChanged
)移動截圖,遍歷獲得截圖移動到哪一個cell
的位置。調用方法moveItemAtIndexPath:toIndexPath:
調換兩個cell
的位置,而且更新數據源的順序。- 第四步 :中止時(
UIGestureRecognizerStateEnded
)移除截圖,顯示cell
。
[iOSUI 進階拖] 拽排序的實現github
DraggingSortswift
LXReorderableCollectionViewFlowLayout數組
CollectionViewCellDragExchange服務器
- 第一步:給
UICollectionviewCell
添加一個長按手勢UILongPressGestureRecognizer
,經過代理傳遞到UIViewController
中。- 第二步:開始長按時(
UIGestureRecognizerStateBegan
)對cell進行截圖而且隱藏cell
。調用beginInteractiveMovementForItem
。- 第三步:移動時(
UIGestureRecognizerStateChanged
)移動截圖。調用updateInteractiveMovementTargetPosition
。- 第四步:中止時(
UIGestureRecognizerStateEnded
)移除截圖,顯示cell
。調用endInteractiveMovement
。
// Support for reordering
@available(iOS 9.0, *)
open func beginInteractiveMovementForItem(at indexPath: IndexPath) -> Bool // returns NO if reordering was prevented from beginning - otherwise YES
@available(iOS 9.0, *)
open func updateInteractiveMovementTargetPosition(_ targetPosition: CGPoint)
@available(iOS 9.0, *)
open func endInteractiveMovement()
@available(iOS 9.0, *)
open func cancelInteractiveMovement()
複製代碼
iOS UICollectionView高級用法(長按自由移動cell)-新app
實現瀑布流的基本原理:找到最短的列,而後把item放到最短的列下面
異步
以下圖所示,因爲第三列最短,因此第八個Item添加到第三列下面。oop
既然要找到 最短的列 ,則就須要用一個數據來保存每一列的Y值,推薦 數組 (相對來講性能比 字典 好)。XRWaterfallLayout使用 字典 來存儲,相比較 數組 的下標直接獲取列的高度, 字典 多作了部分
哈希操做
。作瀑布流,圖片的尺寸就多是不固定的,圖片的尺寸能夠服務器提早返回,而後cell
直接設置大小。post
主要須要重寫三個系統方法:詳情參考實現:XRWaterfallLayout 一、- (void)prepareLayout
二、- (CGSize)collectionViewContentSize
三、- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
iOS9
後
UICollectionView
的頭部視圖也能像tableView
的header
同樣出現懸浮掛住的效果。
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
//header
flowLayout.sectionHeadersPinToVisibleBounds = YES;
//footer
flowLayout.sectionFootersPinToVisibleBounds = YES;
複製代碼
iOS9.0
前須要自定義
UICollectionViewFlowLayout
#import <UIKit/UIKit.h>
@protocol LZSFloatHeaderFlowLayoutDelegate <NSObject>
-(void)sectionDidFloat:(NSInteger)section;
@end
@interface LZSFloatHeaderFlowLayout : UICollectionViewFlowLayout
@property (nonatomic, weak) id<LZSFloatHeaderFlowLayoutDelegate> mDelegate;
@end
複製代碼
#import "LZSFloatHeaderFlowLayout.h"
@interface LZSFloatHeaderFlowLayout()
@property (nonatomic, strong) NSMutableDictionary<NSNumber*, NSNumber*>* mSectionOffsetYDic;
@end
@implementation LZSFloatHeaderFlowLayout
-(NSMutableDictionary<NSNumber *,NSNumber *> *)mSectionOffsetYDic {
if ( !_mSectionOffsetYDic ) {
_mSectionOffsetYDic = [NSMutableDictionary dictionary];
}
return _mSectionOffsetYDic;
}
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
for (NSUInteger idx=0; idx<[answer count]; idx++) {
UICollectionViewLayoutAttributes *layoutAttributes = answer[idx];
if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
[missingSections addIndex:layoutAttributes.indexPath.section]; // remember that we need to layout header for this section
}
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
[answer removeObjectAtIndex:idx]; // remove layout of header done by our super, we will do it right later
idx--;
}
}
// layout all headers needed for the rect using self code
[missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
atIndexPath:indexPath];
[answer addObject:layoutAttributes];
}];
return answer;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind
atIndexPath:indexPath];
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
UICollectionView * const cv = self.collectionView;
CGPoint const contentOffset = cv.contentOffset;
CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY);
if (indexPath.section+1 < [cv numberOfSections]) {
NSIndexPath* tIndexPath = [NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]
UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind
atIndexPath:tIndexPath];
nextHeaderOrigin = nextHeaderAttributes.frame.origin;
}
CGRect frame = attributes.frame;
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));
}
else { // UICollectionViewScrollDirectionHorizontal
frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame));
}
attributes.zIndex = 1024;
attributes.frame = frame;
if ( self.mSectionOffsetYDic[@(indexPath.section)] && (self.mSectionOffsetYDic[@(indexPath.section)].integerValue != frame.origin.y) ) {
if ( [self.mDelegate respondsToSelector:@selector(sectionDidFloat:)] ) {
[self.mDelegate sectionDidFloat:indexPath.section];
}
}
self.mSectionOffsetYDic[@(indexPath.section)] = @(frame.origin.y);
}
return attributes;
}
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind
atIndexPath:indexPath];
return attributes;
}
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind
atIndexPath:indexPath];
return attributes;
}
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
return YES;
}
複製代碼