更新了问题。当视图滚动时,我很难在集合视图中重新排序项目。这样做的原因是重新排序项目的代码在UILongpress手势的UIGestureRecognizerStateChanged内。因此,当视图滚动并且用户的手指在屏幕边缘处静止时,不会调用UILongpress手势中的重新排序代码。如果我只是插入重新排序的代码:
// Is destination valid and is it different from source?
if (indexPath && ![indexPath isEqual:sourceIndexPath]) {
// ... update data source.
[self.imageArray exchangeObjectAtIndex:indexPath.row withObjectAtIndex:sourceIndexPath.row];
// ... move the rows.
[self.collectionView moveItemAtIndexPath:sourceIndexPath toIndexPath:indexPath];
// ... and update source so it is in sync with UI changes.
sourceIndexPath = indexPath;
进入autoscrollTimerFired方法后,项目的索引路径将不再正确,因为集合视图已滚动到用户静态手指下的新位置。
以下完整代码。建议好吗?
- (void)longPressGestureRecognized:(id)sender {
UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
UIGestureRecognizerState state = longPress.state;
CGPoint location = [longPress locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
static UIView *snapshot = nil; ///< A snapshot of the row user is moving.
static NSIndexPath *sourceIndexPath = nil; ///< Initial index path, where gesture begins.
switch (state) {
case UIGestureRecognizerStateBegan: {
if (indexPath) {
[self.deleteButton removeFromSuperview];
self.isDeleteActive = NO;
sourceIndexPath = indexPath;
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
// Take a snapshot of the selected row using helper method.
snapshot = [self customSnapshoFromView:cell];
// Add the snapshot as subview, centered at cell's center...
__block CGPoint center = cell.center;
snapshot.center = center;
snapshot.alpha = 0.0;
[self.collectionView addSubview:snapshot];
[UIView animateWithDuration:0.25 animations:^{
// Offset for gesture location.
center.x = location.x;
snapshot.center = center;
snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
snapshot.alpha = 0.98;
cell.alpha = 0.0;
} completion:^(BOOL finished) {
cell.hidden = YES;
}];
}
break;
}
case UIGestureRecognizerStateChanged: {
CGPoint center = snapshot.center;
center.x = location.x;
snapshot.center = center;
[self maybeAutoscrollForSnapshot:snapshot];
// Is destination valid and is it different from source?
if (indexPath && ![indexPath isEqual:sourceIndexPath]) {
// ... update data source.
[self.imageArray exchangeObjectAtIndex:indexPath.row withObjectAtIndex:sourceIndexPath.row];
// ... move the rows.
[self.collectionView moveItemAtIndexPath:sourceIndexPath toIndexPath:indexPath];
// ... and update source so it is in sync with UI changes.
sourceIndexPath = indexPath;
}
break;
}
default: {
// Clean up.
if(_autoscrollTimer)
{
[_autoscrollTimer invalidate]; _autoscrollTimer = nil;
}
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:sourceIndexPath];
cell.hidden = NO;
cell.alpha = 0.0;
[UIView animateWithDuration:0.25 animations:^{
snapshot.center = cell.center;
snapshot.transform = CGAffineTransformIdentity;
snapshot.alpha = 0.0;
cell.alpha = 1.0;
} completion:^(BOOL finished) {
sourceIndexPath = nil;
[snapshot removeFromSuperview];
snapshot = nil;
}];
break;
}
}
}
- (void)maybeAutoscrollForSnapshot:(UIImageView *)snapshot
{
_autoscrollDistance = 0;
if (CGRectGetMaxX(snapshot.frame) < self.collectionView.collectionViewLayout.collectionViewContentSize.width)
{
// only autoscroll if the content is larger than the view
if (self.collectionView.collectionViewLayout.collectionViewContentSize.width > self.view.frame.size.width)
{
float distanceFromTop = snapshot.center.x - CGRectGetMinX(self.collectionView.bounds);
float distanceFromBottom = CGRectGetMaxX(self.collectionView.bounds) - snapshot.center.x;
//NSLog(@"dist from left %f", distanceFromTop);
if (distanceFromTop < kAutoScrollingThreshold) {
_autoscrollDistance = [self autoscrollDistanceForProximityToEdge:distanceFromTop] * -1; // if scrolling up distance is negative
//NSLog(@"left dist %f", _autoscrollDistance);
} else if (distanceFromBottom < kAutoScrollingThreshold) {
_autoscrollDistance = [self autoscrollDistanceForProximityToEdge:distanceFromBottom];
//NSLog(@"right dist %f", _autoscrollDistance);
}
}
}
// if no autoscrolling, stop and clear timer
if (_autoscrollDistance == 0) {
[_autoscrollTimer invalidate];
_autoscrollTimer = nil;
}
// otherwise create and start timer (if we don't already have a timer going)
else if (_autoscrollTimer == nil) {
_autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 60.0)
target:self
selector:@selector(autoscrollTimerFired:)
userInfo:snapshot
repeats:YES];
}
}
- (float)autoscrollDistanceForProximityToEdge:(float)proximity {
// the scroll distance grows as the proximity to the edge decreases, so that moving the thumb
// further over results in faster scrolling.
return ceilf((kAutoScrollingThreshold - proximity) / 5.0);
}
- (void)legalizeAutoscrollDistance {
// makes sure the autoscroll distance won't result in scrolling past the content of the scroll view
float minimumLegalDistance = (self.collectionView.contentOffset.x + self.collectionView.contentInset.left) * -1;
float maximumLegalDistance = self.collectionView.collectionViewLayout.collectionViewContentSize.width - (self.view.frame.size.width + self.collectionView.contentOffset.x);
//NSLog(@"min dist %f", minimumLegalDistance);
//NSLog(@"max dist %f", maximumLegalDistance);
_autoscrollDistance = MAX(_autoscrollDistance, minimumLegalDistance);
_autoscrollDistance = MIN(_autoscrollDistance, maximumLegalDistance);
//NSLog(@"autoscroll distance %f", _autoscrollDistance);
}
- (void)autoscrollTimerFired:(NSTimer*)timer {
// NSLog(@"autoscrolling: %.2f",_autoscrollDistance);
[self legalizeAutoscrollDistance];
// autoscroll by changing content offset
CGPoint contentOffset = [self.collectionView contentOffset];
contentOffset.x += _autoscrollDistance;
//NSLog(@"%f",contentOffset.x);
[self.collectionView setContentOffset:contentOffset];
// adjust thumb position so it appears to stay still
UIImageView *snapshot = (UIImageView *)[timer userInfo];
snapshot.center = CGPointMake(snapshot.center.x + _autoscrollDistance, snapshot.center.y);
}
答案 0 :(得分:0)
当您调用maybeAutoscrollForSnapshot函数时,将发件人(UILongPressGestureRecognizer
)保存在UIGestureRecognizerStateChanged
中,然后让计时器使用您保存的此手势识别器对象调用longPressGestureRecognized
。手势识别器将具有相对于UIWindow的相同位置,但是当您计算indexPath
时,它应该是正确的,因为scrollView已滚动。
作为旁注,当你到达边缘时,你真的需要让视图滚动吗?
我实现了相同的东西,但没有autoscroll部分,它工作正常。
你有这么长的列表,如果它自动滚动会有帮助吗?