Skip to content

Commit

Permalink
[Collections] - Added autoscroll functionality to MDCCollectionViewEd…
Browse files Browse the repository at this point in the history
…itor class

Summary: MDC_#680 - Added autoscroll functionality to MDCCollections while editing

Reviewers: randallli, O1 Material components iOS

Reviewed By: randallli, O1 Material components iOS

Subscribers: randallli

Tags: #material_components_ios

Differential Revision: http://codereview.cc/D1665
  • Loading branch information
ShepJGoogle committed Sep 26, 2016
1 parent e92b8bc commit 54e319f
Showing 1 changed file with 83 additions and 0 deletions.
83 changes: 83 additions & 0 deletions components/Collections/src/private/MDCCollectionViewEditor.m
Expand Up @@ -40,6 +40,19 @@
static const NSTimeInterval kDismissalAnimationDuration = 0.3;
static const NSTimeInterval kRestoreAnimationDuration = 0.2;

// Distance from collection view bounds that reorder panning should trigger autoscroll.
static const CGFloat kMDCAutoscrollPanningBuffer = 60.0f;

// Distance collection view should offset during autoscroll.
static const CGFloat kMDCAutoscrollPanningOffset = 10.0f;

/** Autoscroll panning direction. */
typedef NS_ENUM(NSInteger, MDCAutoscrollPanningDirection) {
kMDCAutoscrollPanningDirectionNone,
kMDCAutoscrollPanningDirectionUp,
kMDCAutoscrollPanningDirectionDown
};

/** A view that uses an MDCShadowLayer as its sublayer. */
@interface ShadowedSnapshotView : UIView
@end
Expand All @@ -64,6 +77,8 @@ @implementation MDCCollectionViewEditor {
CGPoint _selectedCellLocation;
CGPoint _initialCellLocation;
ShadowedSnapshotView *_cellSnapshot;
CADisplayLink *_autoscrollTimer;
MDCAutoscrollPanningDirection _autoscrollPanningDirection;
}

@synthesize collectionView = _collectionView;
Expand Down Expand Up @@ -360,6 +375,8 @@ - (void)handleLongPressGesture:(UILongPressGestureRecognizer *)recognizer {
}
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateEnded: {
// Stop autoscroll.
[self stopAutoscroll];
NSIndexPath *currentIndexPath = _reorderingCellIndexPath;
if (currentIndexPath) {
UICollectionViewLayoutAttributes *attributes = [_collectionView.collectionViewLayout
Expand Down Expand Up @@ -418,6 +435,18 @@ - (void)panToReorderWithRecognizer:(UIPanGestureRecognizer *)recognizer {
return;
}

// Autoscroll if the cell is dragged out of the collectionView's bounds.
CGFloat buffer = kMDCAutoscrollPanningBuffer;
if (_selectedCellLocation.y < CGRectGetMinY(self.collectionView.bounds) + buffer) {
[self startAutoscroll];
_autoscrollPanningDirection = kMDCAutoscrollPanningDirectionUp;
} else if (_selectedCellLocation.y > (CGRectGetMaxY(self.collectionView.bounds) - buffer)) {
[self startAutoscroll];
_autoscrollPanningDirection = kMDCAutoscrollPanningDirectionDown;
} else {
[self stopAutoscroll];
}

// Check delegate for permission to move item.
if ([_delegate
respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:toIndexPath:)]) {
Expand Down Expand Up @@ -724,4 +753,58 @@ - (CGFloat)dismissalAlphaForTranslationX:(CGFloat)translationX {
return kDismissalMinimumAlpha + (1 - kDismissalMinimumAlpha) * (1 - dismissalPercentage);
}

#pragma mark - Reordering Autoscroll

- (void)startAutoscroll {
if (_autoscrollTimer) {
[self stopAutoscroll];
}
_autoscrollTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(autoscroll:)];
[_autoscrollTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stopAutoscroll {
if (_autoscrollTimer) {
[_autoscrollTimer invalidate];
_autoscrollTimer = nil;
_autoscrollPanningDirection = kMDCAutoscrollPanningDirectionNone;
}
}

- (void)autoscroll:(CADisplayLink *)sender {
// Scrolls at each tick of CADisplayLink by setting scroll contentOffset. Animation is performed
// within UIView animation block rather than directly calling -setContentOffset:animated: method
// in order to prevent jerkiness in scrolling.
BOOL isPanningDown = _autoscrollPanningDirection == kMDCAutoscrollPanningDirectionDown;
CGFloat yOffset = kMDCAutoscrollPanningOffset * (isPanningDown ? 1 : -1);
CGFloat contentYOffset = self.collectionView.contentOffset.y;

// Quit early if scrolling past collection view bounds.
if ((!isPanningDown && contentYOffset <= 0) ||
(isPanningDown &&
contentYOffset >=
self.collectionView.contentSize.height - CGRectGetHeight(self.collectionView.bounds))) {
[self stopAutoscroll];
return;
}

// When autoscrolling, keep cell snapshot transform to longpress position.
CGAffineTransform snapshotTransform =
CATransform3DGetAffineTransform(_cellSnapshot.layer.transform);
snapshotTransform.ty += yOffset;

[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.collectionView.contentOffset =
CGPointMake(0, MAX(0, contentYOffset + yOffset));

// Transform snapshot position when panning.
_cellSnapshot.layer.transform =
CATransform3DMakeAffineTransform(snapshotTransform);
}
completion:nil];
}

@end

0 comments on commit 54e319f

Please sign in to comment.