在UILongpress手势中,UICollectionView滚动

时间:2015-04-22 20:56:17

标签: ios uicollectionview

更新了问题。当视图滚动时,我很难在集合视图中重新排序项目。这样做的原因是重新排序项目的代码在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);

}

1 个答案:

答案 0 :(得分:0)

当您调用maybeAutoscrollForSnapshot函数时,将发件人(UILongPressGestureRecognizer)保存在UIGestureRecognizerStateChanged中,然后让计时器使用您保存的此手势识别器对象调用longPressGestureRecognized。手势识别器将具有相对于UIWindow的相同位置,但是当您计算indexPath时,它应该是正确的,因为scrollView已滚动。

作为旁注,当你到达边缘时,你真的需要让视图滚动吗?
我实现了相同的东西,但没有autoscroll部分,它工作正常。

你有这么长的列表,如果它自动滚动会有帮助吗?