浏览代码

avoid crash and make collectionview scrollable again

Carola Nitz 11 年之前
父节点
当前提交
625d6df148

+ 3 - 2
Sources/VLCFolderCollectionViewFlowLayout.h

@@ -10,11 +10,12 @@
  * Refer to the COPYING file of the official project for license.
  *****************************************************************************/
 
-@interface VLCFolderCollectionViewFlowLayout : UICollectionViewFlowLayout
+@interface VLCFolderCollectionViewFlowLayout : UICollectionViewFlowLayout <UIGestureRecognizerDelegate>
 
 @property (assign, nonatomic) CGFloat scrollingSpeed;
 @property (assign, nonatomic) UIEdgeInsets scrollingTriggerEdgeInsets;
-@property (strong, nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer;
+@property (nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;
+@property (nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer;
 
 @end
 

+ 95 - 33
Sources/VLCFolderCollectionViewFlowLayout.m

@@ -75,6 +75,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
     CGPoint _panTranslationInCollectionView;
     CADisplayLink *_displayLink;
     UIView *_folderView;
+    BOOL _didPan;
 }
 
 @end
@@ -87,14 +88,23 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
 }
 
 - (void)setupCollectionView {
+    _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
+                                                                                action:@selector(handleLongPressGesture:)];
+    _longPressGestureRecognizer.delegate = self;
 
-    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
-                                                                    action:@selector(handlePanGesture:)];
+    // Links the default long press gesture recognizer to the custom long press gesture recognizer we are creating now
+    // by enforcing failure dependency so that they doesn't clash.
     for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {
-        if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
-            [gestureRecognizer requireGestureRecognizerToFail:_panGestureRecognizer];
+        if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
+            [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];
+        }
     }
 
+    [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
+
+    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
+                                                                    action:@selector(handlePanGesture:)];
+    _panGestureRecognizer.delegate = self;
     [self.collectionView addGestureRecognizer:_panGestureRecognizer];
 
     // Useful in multiple scenarios: one common scenario being when the Notification Center drawer is pulled down
@@ -137,7 +147,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
 - (void)invalidateLayoutIfNecessary {
     NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:_currentView.center];
     NSIndexPath *previousIndexPath = _selectedItemIndexPath;
-    
+
     if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) {
         _currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
         [_folderView removeFromSuperview];
@@ -152,7 +162,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
     }
     [self.collectionView insertSubview:_folderView atIndex:0];
 
-    if (!CGPointEqualToPoint(_folderView.center,cell.center)) 
+    if (!CGPointEqualToPoint(_folderView.center,cell.center))
         _folderView.frame = cell.frame;
 
     [UIView
@@ -178,7 +188,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
         if (direction == oldDirection)
             return;
     }
-    
+
     [self invalidatesScrollTimer];
 
     _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleScroll:)];
@@ -193,7 +203,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
     LXScrollingDirection direction = (LXScrollingDirection)[displayLink.LX_userInfo[kLXScrollingDirectionKey] integerValue];
     if (direction == LXScrollingDirectionUnknown)
         return;
-    
+
     CGSize frameSize = self.collectionView.bounds.size;
     CGSize contentSize = self.collectionView.contentSize;
     CGPoint contentOffset = self.collectionView.contentOffset;
@@ -201,33 +211,33 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
     // and it would diverge from the view's center resulting in a "cell is slipping away under finger"-bug.
     CGFloat distance = rint(self.scrollingSpeed / LX_FRAMES_PER_SECOND);
     CGPoint translation = CGPointZero;
-    
+
     switch(direction) {
         case LXScrollingDirectionUp: {
             distance = -distance;
             CGFloat minY = 0.0f;
-            
+
             if ((contentOffset.y + distance) <= minY)
                 distance = -contentOffset.y;
-            
+
             translation = CGPointMake(0.0f, distance);
         } break;
         case LXScrollingDirectionDown: {
             CGFloat maxY = MAX(contentSize.height, frameSize.height) - frameSize.height;
-            
+
             if ((contentOffset.y + distance) >= maxY)
                 distance = maxY - contentOffset.y;
-            
+
             translation = CGPointMake(0.0f, distance);
         } break;
         case LXScrollingDirectionLeft: {
 
             distance = -distance;
             CGFloat minX = 0.0f;
-            
+
             if ((contentOffset.x + distance) <= minX)
                 distance = -contentOffset.x;
-            
+
             translation = CGPointMake(distance, 0.0f);
         } break;
         case LXScrollingDirectionRight: {
@@ -242,21 +252,18 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
             // Do nothing...
         } break;
     }
-    
     _currentViewCenter = LXS_CGPointAdd(_currentViewCenter, translation);
     _currentView.center = LXS_CGPointAdd(_currentViewCenter, _panTranslationInCollectionView);
     self.collectionView.contentOffset = LXS_CGPointAdd(contentOffset, translation);
 }
 
-- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer {
+- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer {
     //keeps the controller from dragging while not in editmode
-
     if (!((VLCPlaylistViewController *)self.delegate).isEditing) return;
 
-    switch (gestureRecognizer.state) {
+    switch(gestureRecognizer.state) {
         case UIGestureRecognizerStateBegan: {
             NSIndexPath *currentIndexPath = [self.collectionView indexPathForItemAtPoint:[gestureRecognizer locationInView:self.collectionView]];
-
             _selectedItemIndexPath = currentIndexPath;
 
             UICollectionViewCell *collectionViewCell = [self.collectionView cellForItemAtIndexPath:_selectedItemIndexPath];
@@ -284,21 +291,58 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
              delay:0.0
              options:UIViewAnimationOptionBeginFromCurrentState
              animations:^{
-                     _currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
-                     highlightedImageView.alpha = 0.0f;
-                     imageView.alpha = 1.0f;
+                 _currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
+                 highlightedImageView.alpha = 0.0f;
+                 imageView.alpha = 1.0f;
              }
              completion:^(BOOL finished) {
-                 [highlightedImageView removeFromSuperview];
+                [highlightedImageView removeFromSuperview];
              }];
 
             [self invalidateLayout];
-            break;
-        }
+        } break;
+        case UIGestureRecognizerStateCancelled:
+        case UIGestureRecognizerStateEnded: {
+            if (_didPan) return;
+
+            NSIndexPath *currentIndexPath = _selectedItemIndexPath;
+
+            if (currentIndexPath) {
+                _selectedItemIndexPath = nil;
+                _currentViewCenter = CGPointZero;
+
+                UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:currentIndexPath];
+
+                [UIView
+                 animateWithDuration:0.3
+                 delay:0.0
+                 options:UIViewAnimationOptionBeginFromCurrentState
+                 animations:^{
+                     _currentView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
+                     _currentView.center = layoutAttributes.center;
+                 }
+                 completion:^(BOOL finished) {
+
+                     [_currentView removeFromSuperview];
+                     _currentView = nil;
+                     [self invalidateLayout];
+
+                 }];
+            }
+        } break;
+
+        default: break;
+    }
+}
+
+- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer {
+
+    switch (gestureRecognizer.state) {
+        case UIGestureRecognizerStateBegan:
+            _didPan = YES;
         case UIGestureRecognizerStateChanged: {
             _panTranslationInCollectionView = [gestureRecognizer translationInView:self.collectionView];
             CGPoint viewCenter = _currentView.center = LXS_CGPointAdd(_currentViewCenter, _panTranslationInCollectionView);
-            
             [self invalidateLayoutIfNecessary];
 
             switch (self.scrollDirection) {
@@ -325,16 +369,16 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
                     }
                 } break;
             }
-
         } break;
         case UIGestureRecognizerStateCancelled:
         case UIGestureRecognizerStateEnded: {
+            _didPan = NO;
             [_folderView removeFromSuperview];
             _folderView = nil;
             NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:_currentView.center];
             NSIndexPath *currentIndexPath = _selectedItemIndexPath;
 
-            if (newIndexPath != nil && ![currentIndexPath isEqual:newIndexPath]) {
+            if (newIndexPath != nil && ![currentIndexPath isEqual:newIndexPath] && ((VLCPlaylistViewController *)self.delegate).isEditing) {
                 [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
                     _currentView.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
                     _currentView.center = [self layoutAttributesForItemAtIndexPath:newIndexPath].center;
@@ -368,7 +412,7 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
 
 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
     NSArray *layoutAttributesForElementsInRect = [super layoutAttributesForElementsInRect:rect];
-    
+
     for (UICollectionViewLayoutAttributes *layoutAttributes in layoutAttributesForElementsInRect) {
         switch (layoutAttributes.representedElementCategory) {
             case UICollectionElementCategoryCell: {
@@ -379,13 +423,12 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
             } break;
         }
     }
-    
     return layoutAttributesForElementsInRect;
 }
 
 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
     UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
-    
+
     switch (layoutAttributes.representedElementCategory) {
         case UICollectionElementCategoryCell: {
             [self applyLayoutAttributes:layoutAttributes];
@@ -394,9 +437,28 @@ static NSString * const kLXCollectionViewKeyPath = @"collectionView";
             // Do nothing...
         } break;
     }
-    
+
     return layoutAttributes;
 }
+#pragma mark - UIGestureRecognizerDelegate methods
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
+    if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
+        return (_selectedItemIndexPath != nil);
+    }
+    return YES;
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
+    if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
+        return [self.panGestureRecognizer isEqual:otherGestureRecognizer];
+    }
+
+    if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
+        return [self.longPressGestureRecognizer isEqual:otherGestureRecognizer];
+    }
+    return NO;
+}
 
 #pragma mark - Key-Value Observing methods
 

+ 3 - 2
Sources/VLCPlaylistCollectionViewCell.m

@@ -41,7 +41,8 @@
 - (void)setEditing:(BOOL)editing animated:(BOOL)animated
 {
     self.isSelectedView.hidden = !editing;
-    if ([_mediaObject isKindOfClass:[MLLabel class]] || [_mediaObject.labels count] == 0)
+
+    if (!([_mediaObject isKindOfClass:[MLFile class]] && [_mediaObject.labels count] > 0))
         [self shake:editing];
     [self selectionUpdate];
     [self _updatedDisplayedInformationForKeyPath:@"editing"];
@@ -266,7 +267,7 @@
 {
     self.titleLabel.text = label.name;
     NSUInteger count = label.files.count;
-    self.subtitleLabel.text = [NSString stringWithFormat:(count == 1) ? NSLocalizedString(@"LIBRARY_TRACKS", @"") : NSLocalizedString(@"LIBRARY_SINGLE_TRACK", @""), count];
+    self.subtitleLabel.text = [NSString stringWithFormat:(count == 1) ? NSLocalizedString(@"LIBRARY_SINGLE_TRACK", @"") : NSLocalizedString(@"LIBRARY_TRACKS", @""), count];
     self.mediaIsUnreadView.hidden = YES;
     self.progressView.hidden = YES;
 }

+ 1 - 1
Sources/VLCPlaylistTableViewCell.m

@@ -239,7 +239,7 @@
 {
     self.titleLabel.text = label.name;
     NSUInteger count = label.files.count;
-    self.subtitleLabel.text = [NSString stringWithFormat:(count == 1) ? NSLocalizedString(@"LIBRARY_TRACKS", @"") : NSLocalizedString(@"LIBRARY_SINGLE_TRACK", @""), count];
+    self.subtitleLabel.text = [NSString stringWithFormat:(count == 1) ? NSLocalizedString(@"LIBRARY_TRACK", @"") : NSLocalizedString(@"LIBRARY_SINGLE_TRACKS", @""), count];
     self.mediaIsUnreadView.hidden = YES;
     self.progressIndicator.hidden = YES;
 }

+ 22 - 9
Sources/VLCPlaylistViewController.m

@@ -53,6 +53,7 @@ static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutoria
     VLCFolderCollectionViewFlowLayout *_folderLayout;
     LXReorderableCollectionViewFlowLayout *_reorderLayout;
     BOOL inFolder;
+    UILongPressGestureRecognizer *_longPressGestureRecognizer;
 }
 
 @property (nonatomic, strong) UITableView *tableView;
@@ -95,8 +96,8 @@ static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutoria
         _collectionView.opaque = YES;
         _collectionView.backgroundColor = [UIColor colorWithWhite:.122 alpha:1.];
         self.view = _collectionView;
-        UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_collectionViewHandleLongPressGesture:)];
-        [_collectionView addGestureRecognizer:longPressGestureRecognizer];
+        _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_collectionViewHandleLongPressGesture:)];
+        [_collectionView addGestureRecognizer:_longPressGestureRecognizer];
         if (SYSTEM_RUNS_IOS7_OR_LATER)
             [_collectionView registerNib:[UINib nibWithNibName:@"VLCFuturePlaylistCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"PlaylistCell"];
         else
@@ -224,9 +225,13 @@ static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutoria
         MLLabel *folder = (MLLabel*) mediaObject;
         inFolder = YES;
         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-            if (_reorderLayout == nil)
-                _reorderLayout = [[LXReorderableCollectionViewFlowLayout alloc] init];
+            for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
+                if (recognizer == _folderLayout.panGestureRecognizer || recognizer == _folderLayout.longPressGestureRecognizer || recognizer == _longPressGestureRecognizer)
+                    [self.collectionView removeGestureRecognizer:recognizer];
+            }
+            _reorderLayout = [[LXReorderableCollectionViewFlowLayout alloc] init];
             [self.collectionView setCollectionViewLayout:_reorderLayout animated:NO];
+            _folderLayout = nil;
         }
         _foundMedia = [[folder.files allObjects] mutableCopy];
         self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(backToAllItems:)];
@@ -905,12 +910,15 @@ static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutoria
         /* UIKit doesn't clear the selection automagically if we leave the editing mode
          * so we need to do so manually */
         if (!editing) {
+            [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
             NSArray *selectedItems = [self.collectionView indexPathsForSelectedItems];
             NSUInteger count = selectedItems.count;
 
             for (NSUInteger x = 0; x < count; x++)
                 [self.collectionView deselectItemAtIndexPath:selectedItems[x] animated:NO];
-        }
+        } else
+            [self.collectionView removeGestureRecognizer:_longPressGestureRecognizer];
+
     } else {
         self.tableView.allowsMultipleSelectionDuringEditing = editing;
         [self.tableView setEditing:editing animated:YES];
@@ -942,10 +950,15 @@ static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutoria
 - (IBAction)backToAllItems:(id)sender
 {
     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
-        [self.collectionView setCollectionViewLayout:_folderLayout];
-        //TODO: find better way than creating a new recognizer
-        UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_collectionViewHandleLongPressGesture:)];
-        [_collectionView addGestureRecognizer:longPressGestureRecognizer];
+        //for some reason the Gesturerecognizer block themselves if not removed manually
+        for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
+            if (recognizer == _reorderLayout.panGestureRecognizer || recognizer == _reorderLayout.longPressGestureRecognizer)
+                [self.collectionView removeGestureRecognizer:recognizer];
+        }
+        _folderLayout = [[VLCFolderCollectionViewFlowLayout alloc] init];
+        [self.collectionView setCollectionViewLayout:_folderLayout animated:NO];
+        _reorderLayout = nil;
+        [_collectionView addGestureRecognizer:_longPressGestureRecognizer];
     }
     inFolder = NO;
     UIBarButtonItem *createFolderItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:@selector(createFolder)];