- One: listen for the time when scrolling stops
- Listen for the time when reloadData finishes refreshing the list
- Three, free drag
- Waterfall flow
- Float headers
One: listen for the time when scrolling stops
Scenario 1: Manually drag the screen to stop
Scenario 2. InvokescrollToRow
stop
Scenario 3. InvocationsetContentOffset
stop
self.tableView.setContentOffset(CGPoint.init(x: 0, y: 0), animated: false)
print("When I execute this line of code, I'm done scrolling.")
Copy the code
Listen for the time when reloadData finishes refreshing the list
Listen for the time when reloadData finishes refreshing the list
- Method 1. Pass
layoutIfNeeded
Method to force a redraw and wait for completion. - Method 2,
reloadData
The method is executed on the main thread, throughGCD
, so that subsequent operations queue inreloadData
Execute later. At a timerunloop
There are two opportunities to executeGCD dispatch main queue
Before sleep and after wake up. Set up thelistView
的layoutIfNeeded
To YES, perform the asynchronous task and redraw the interface when it is about to enter sleep. - Method 3: Customize
UICollectionView
,UITableView
.layoutSubviews
After areloadData
Done (complex, but better understood method 1)
Three, free drag
First, iOS9 before thinking:
- The first step:
UICollectionviewCell
Add a long press gestureUILongPressGestureRecognizer
, passed through the proxy toUIViewController
In the.- The second step: Start adding hours (
UIGestureRecognizerStateBegan
) tocell
Take a screenshot and hide itcell
.- The third step: When moving (
UIGestureRecognizerStateChanged
) move the screenshot, iterate to get which screenshot to move tocell
The location of the. A method is calledmoveItemAtIndexPath:toIndexPath:
Change the twocell
And update the order of the data sources.- The fourth step: Stop (
UIGestureRecognizerStateEnded
) remove the screenshot and displaycell
.
Reference blog:
[iOSUI advanced drag] drop sort implementation
DraggingSort
LXReorderableCollectionViewFlowLayout
XWDragCellCollectionView
CollectionViewCellDragExchange
Two, iOS9 after thinking:
- Step 1: Here
UICollectionviewCell
Add a long press gestureUILongPressGestureRecognizer
, passed through the proxy toUIViewController
In the.- Step 2: Start adding hours (
UIGestureRecognizerStateBegan
) Take a screenshot of the cell and hide itcell
. callbeginInteractiveMovementForItem
.- Step 3: When moving (
UIGestureRecognizerStateChanged
) Move screenshot. callupdateInteractiveMovementTargetPosition
.- Step 4: Stop (
UIGestureRecognizerStateEnded
) remove the screenshot and displaycell
. callendInteractiveMovement
.
// Support forReordering @ the available (iOS 9.0. *) open func beginInteractiveMovementForItem (ats indexPath: IndexPath) -> Bool // returns NOifReordering was prevented from common-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()Copy the code
Reference blog:
IOS UICollectionView Advanced Usage (Hold down free move cell)- New
Waterfall flow
The basic principle for implementing waterfall flow is to find the shortest column and put item under the shortest column
As you can see in the figure below, the eighth Item is added below the third column because the third column is the shortest.
Since you want to find the shortest column, you need a data store for each column’s Y value, which is recommended as an array (relatively better than a dictionary). XRWaterfallLayout uses a dictionary for storage, which is partially hashed more than arrays whose subscripts directly retrieve column heights. As a waterfall stream, the size of the image may not be fixed. The size of the image can be returned by the server in advance, and the cell can set the size directly.
Three system methods need to be rewritten: XRWaterfallLayout, 1 – (void) prepareLayout 2, 3 – (CGSize) collectionViewContentSize, – (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
Float headers
One, in theiOS9
after
UICollectionView’s header view can also hover like a tableView’s header.
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
//header
flowLayout.sectionHeadersPinToVisibleBounds = YES;
//footer
flowLayout.sectionFootersPinToVisibleBounds = YES;
Copy the code
Second, iniOS9.0
before
Need to customize UICollectionViewFlowLayout
#import <UIKit/UIKit.h>
@protocol LZSFloatHeaderFlowLayoutDelegate <NSObject>
-(void)sectionDidFloat:(NSInteger)section;
@end
@interface LZSFloatHeaderFlowLayout : UICollectionViewFlowLayout
@property (nonatomic, weak) id<LZSFloatHeaderFlowLayoutDelegate> mDelegate;
@end
Copy the code
#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;
}
Copy the code