UICollectionView "прокручивается" в диспетчере приложений iOS7?

На любом iPhone 2014+ или iPad дважды щелкните кнопку "Дом", чтобы увидеть "диспетчер приложений"

enter image description here

Это левый правый UICollectionView, но у него есть жест "салфетки".. проведите пальцем вверх. Как это делается? Это не так просто "удалить" ячейку из UICollectionView.


Сноска для гуглеров.. для общей проблемы "отслаивания", "отрыва", одной ячейки из коллекции, здесь полное опрятное объяснение: https://stackoverflow.com/a/24339705/294884 Надеюсь, это поможет кому-то.

Ответ 1

Это может быть намного проще, чем предлагают комментарии к вашему вопросу.

Ваша ячейка должна содержать представление (то, что вы собираетесь перетащить), и вы добавите в это представление UIPanGestureRecognizer.

В методе действий жестов вы перемещаете представление вверх или вниз, и когда он становится достаточно далеко от того, что вы хотите удалить, вы просто анимируете его. Здесь есть много вопросов, касающихся этой части.

Это оставляет пробел в вашей коллекции, и теперь вам нужно перемещать вещи. Оказывается, это довольно просто:

[_collectionView performBatchUpdates:^{
   [_collectionView deleteItemsAtIndexPaths:@[indexPath]];
} completion:^(BOOL finished) {
     // you might want to remove the data from the data source here so the view doesn't come back to life when the collection view is reloaded.
}];

Материал справа от удаленной ячейки скользит, и мы все хорошо.

Еще одна проблема, с которой вы справитесь: убедитесь, что ваш распознаватель жестов и вид коллекций играют хорошо вместе. К счастью, это тоже не слишком сложно.

[_collectionView.panGestureRecognizer requireGestureRecognizerToFail:pgr]; //where pgr is the recognizer you made for dragging the view off

Это означает, что для жесты панорамы просмотра коллекции делать свою вещь, ваш должен потерпеть неудачу. Таким образом, вы захотите настроить свои настройки таким образом, чтобы они работали только при панорамировании вверх и вниз, и пусть просмотр коллекции все еще делает свое дело для скобок слева направо. В вашем делерителе распознавателей жестов выполните следующий метод, который просто проверяет, больше ли вы перемещаетесь по оси x или оси y.

-(BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
    CGPoint translation =[gestureRecognizer translationInView:self.view];

    return(translation.x * translation.x > translation.y * translation.y);
}

Ответ 2

Я искал эту функциональность и с помощью предложения @mbehan подделывал эту функцию с помощью UICollectionView.

Что я сделал, я добавил представление меньшего размера в ячейке коллекции (Прозрачный фон) и добавил один жест на вкладке CollectionView (не на каждую ячейку), а затем на жесте жесткости я перемещаю вид, и он выглядит как ячейка двигается. После того, как представление достигнет некоторого момента, сначала скройте его, а затем удалит ячейку просмотра коллекции.

Иерархия ячеек: collectionViewCell → Просмотр (значение тега == 2) → UILabel (значение тега = 1) Ярлык используется только для целей компоновщика.

Я отправляю свой код ниже:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = (UICollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"Cards" forIndexPath:indexPath];
    UILabel *lblNumber = (UILabel*)[cell.contentView viewWithTag:1];
    UIView *viewTouch = (UIView*)[cell.contentView viewWithTag:2];
    [viewTouch setHidden:NO];
    [lblNumber setText:arrCards[indexPath.row]];

    return cell;
}


- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 50, 0, 30);
  }

-(BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{

    if([gestureRecognizer isEqual:panGesture]) {
    CGPoint point = [(UIPanGestureRecognizer*)gestureRecognizer translationInView:collectionView_];
        if(point.x != 0) { //adjust this condition if you want some leniency on the X axis
        //The translation was on the X axis, i.e. right/left,
        //so this gesture recognizer shouldn't do anything about it
        return NO;
        }
   }
   return YES;
}

- (IBAction)panGestureCalled:(UIPanGestureRecognizer *)sender {
    yFromCenter = [sender translationInView:collectionView_].y; //%%% positive for up, negative for down

    UIView *view = sender.view;
    CGPoint location = [view.superview convertPoint:view.center toView:collectionView_];
    NSIndexPath *indexPath = [collectionView_ indexPathForItemAtPoint:location];
    UICollectionViewCell *cell = [collectionView_ cellForItemAtIndexPath:indexPath];
    UIView *touchView = (UIView*)[cell.contentView viewWithTag:2];


    switch (sender.state) {
      case UIGestureRecognizerStateBegan:{
        originalPoint = touchView.center;
        break;
    };
      case UIGestureRecognizerStateChanged:{
        touchView.center = CGPointMake(originalPoint.x , originalPoint.y + yFromCenter);

        break;
    };
        //%%% let go of the card
      case UIGestureRecognizerStateEnded: {
        CGFloat velocityY = (0.2*[(UIPanGestureRecognizer*)sender velocityInView:collectionView_].y);

        if (velocityY < -30 && yFromCenter<0) {
            [self hideView:touchView withDuration:0.2 andIndexPath:indexPath];

        }else if ((yFromCenter< 0 && yFromCenter > -200) || yFromCenter > 0){

            CGFloat animationDuration = (ABS(velocityY)*.0002)+.2;
            [self resettleViewToOriginalPosition:touchView andDuration:animationDuration];

        }else
            [self hideView:touchView withDuration:0.2 andIndexPath:indexPath];

    };
        break;
      case UIGestureRecognizerStatePossible:break;
      case UIGestureRecognizerStateCancelled:break;
      case UIGestureRecognizerStateFailed:break;
  }
}


-(void)resettleViewToOriginalPosition:(UIView*)view andDuration:(float)duration{
[UIView animateWithDuration:duration
                      delay:0.0f
                    options: UIViewAnimationOptionCurveEaseOut
                 animations:^
 {
     [view setCenter:originalPoint];
 }
                 completion:^(BOOL finished)
 {

 }];
}
- (void)hideView:(UIView*)view withDuration:(float)duration andIndexPath:(NSIndexPath*)indexPath
{

[UIView animateWithDuration:duration
                      delay:0.0f
                    options: UIViewAnimationOptionCurveEaseOut
                 animations:^
 {
     CGRect frame = view.frame;
     frame.origin.y = -300;
     view.frame = frame;
 }
                 completion:^(BOOL finished)
 {
     [view setHidden:YES];
     CGRect frame = view.frame;
     frame.origin.y = 39;
     view.frame = frame;
     NSLog(@"View is hidden.");

     [arrCards removeObjectAtIndex:indexPath.row];
     [collectionView_ performBatchUpdates:^{
         [collectionView_ deleteItemsAtIndexPaths:@[indexPath]];
     } completion:^(BOOL finished) {
         // you might want to remove the data from the data source here so the view doesn't come back to life when the collection view is reloaded.
     }];
 }];
}

и сохраняйте pagingEnabled от CollectionView до NO, и тогда это должно быть хорошо, чтобы идти.