2012-11-19 14 views
8

Mam UICollectionView z UIImageView w każdej komórce, teraz chcę dodać Copy objaśnienie, jak w Photos.app:Kopiowanie Callout w UICollectionView

enter image description here

Widziałem tę metodę w UICollectionViewDelegate:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath { 
    return YES; 
} 

Po kilku dodatkowych minut badań znalazłem UIMenuController Ćwiczenia, jak zrozumiałem, że muszę z nim pracować, aby dostać się do menu, ale w każdym razie, myślę, że musi być bardziej prosty sposób, a następnie tworząc UIGestureRecognizer i cre na przykład pozycjonowanie itp. mojego UIMenu.

Czy jestem na dobrej drodze? Jak możesz wdrożyć tę funkcję?

Odpowiedz

9

Jest to pełne rozwiązanie:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath { 
     return YES; 
    } 

- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 
     if ([NSStringFromSelector(action) isEqualToString:@"copy:"]) 
      return YES; 
     else 
      return NO; 
    } 

- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 
     if ([NSStringFromSelector(action) isEqualToString:@"copy:"]) { 
      UIPasteboard *pasteBoard = [UIPasteboard pasteboardWithName:UIPasteboardNameGeneral create:NO]; 
      pasteBoard.persistent = YES; 
      NSData *capturedImageData = UIImagePNGRepresentation([_capturedPhotos objectAtIndex:indexPath.row]); 
      [pasteBoard setData:capturedImageData forPasteboardType:(NSString *)kUTTypePNG]; 
     } 
    } 

W moim przypadku, jestem pozwalając tylko funkcję kopiowania w moim CollectionView, a jeśli kopia jest wciśnięty, mam skopiowanie obrazu, który znajduje się wewnątrz komórka do PasteBoard.

+0

Tak trzeba tylko te 3 metody. Coś jeszcze jest niepotrzebne. –

+0

Dzięki, wypróbowałem Twoje rozwiązanie podczas pisania UIMenuItem * menuItem = [[UIMenuItem alloc] initWithTitle: @ "Edit" akcja: @selector (editPlate :)]; wymaga to jednak posiadania metody editPlate, ale chciałbym użyć funkcji performAction, dzięki czemu mogę poznać identyfikator komórki. Jak znaleźć pozycję menu? – Dejell

18

Tak, jesteś na dobrej drodze. Możesz także zaimplementować niestandardowe akcje poza cięciem, kopiowaniem, wklejaniem za pomocą tej techniki.

Custom actions for the UICollectionView

// ViewController.h 
@interface ViewController : UICollectionViewController 

// ViewController.m 
-(void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.collectionView.delegate = self; 

    UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Custom Action" 
                 action:@selector(customAction:)]; 
    [[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObject:menuItem]]; 

} 

#pragma mark - UICollectionViewDelegate methods 
- (BOOL)collectionView:(UICollectionView *)collectionView 
     canPerformAction:(SEL)action 
    forItemAtIndexPath:(NSIndexPath *)indexPath 
      withSender:(id)sender { 
    return YES; // YES for the Cut, copy, paste actions 
} 

- (BOOL)collectionView:(UICollectionView *)collectionView 
shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath { 
    return YES; 
} 

- (void)collectionView:(UICollectionView *)collectionView 
     performAction:(SEL)action 
    forItemAtIndexPath:(NSIndexPath *)indexPath 
      withSender:(id)sender { 
    NSLog(@"performAction"); 
} 

#pragma mark - UIMenuController required methods 
- (BOOL)canBecomeFirstResponder { 
    // NOTE: The menu item will on iOS 6.0 without YES (May be optional on iOS 7.0) 
    return YES; 
} 

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 
    NSLog(@"canPerformAction"); 
    // The selector(s) should match your UIMenuItem selector 
    if (action == @selector(customAction:)) { 
     return YES; 
    } 
    return NO; 
} 

#pragma mark - Custom Action(s) 
- (void)customAction:(id)sender { 
    NSLog(@"custom action! %@", sender); 
} 

Uwaga: iOS 7.0 Zmiany Zachowanie

  1. W podklasie UICollectionViewCell trzeba dodać niestandardowe metody działania, czy pojawi się nic.

    // Cell.m 
    #import "Cell.h" 
    
    @implementation Cell 
    
    - (id)initWithFrame:(CGRect)frame { 
        self = [super initWithFrame:frame]; 
        if (self) { 
         // custom logic 
        } 
        return self; 
    } 
    
    - (void)customAction:(id)sender { 
        NSLog(@"Hello"); 
    
        if([self.delegate respondsToSelector:@selector(customAction:forCell:)]) { 
         [self.delegate customAction:sender forCell:self]; 
        } 
    } 
    @end 
    
  2. Musisz utworzyć protokół delegata i ustawić ją na każdej komórce oddzwonić do UIController który utrzymuje swoją UICollectionView. Dzieje się tak dlatego, że komórka nie powinna mieć nic wspólnego z modelem, ponieważ zajmuje się tylko wyświetlaniem treści.

    // Cell.h 
    #import <UIKit/UIKit.h> 
    
    @class Cell; // Forward declare Custom Cell for the property 
    
    @protocol MyMenuDelegate <NSObject> 
    @optional 
    - (void)customAction:(id)sender forCell:(Cell *)cell; 
    @end 
    
    @interface Cell : UICollectionViewCell 
    
    @property (strong, nonatomic) UILabel* label; 
    @property (weak, nonatomic) id<MyMenuDelegate> delegate; 
    @end 
    
  3. W swojej ViewController lub podklasy UICollectionViewController musisz być zgodne z protokołem i wdrożenie nowej metody.

    // ViewController.m 
    @interface ViewController() <MyMenuDelegate> 
    @end 
    
    // @implementation ViewController ... 
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; 
    { 
        Cell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath]; 
        cell.delegate = self; 
        return cell; 
    } 
    // ... 
    
    // Delegate method for iOS 7.0 to get action from UICollectionViewCell 
    - (void)customAction:(id)sender forCell:(Cell *)cell { 
        NSLog(@"custom action! %@", sender); 
    } 
    

    Custom longpress action menu for UICollectionView

  4. Opcjonalnie: W UIView Podklasa można zastąpić domyślny Wytnij, Kopiuj, Wklej, jeśli wdrożyć metoda canPerformAction tutaj, zamiast w UIViewController. W przeciwnym razie zachowanie pokaże domyślne metody przed niestandardowymi metodami.

    // Cell.m 
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 
        NSLog(@"canPerformAction"); 
        // The selector(s) should match your UIMenuItem selector 
    
        NSLog(@"Sender: %@", sender); 
        if (action == @selector(customAction:)) { 
         return YES; 
        } 
        return NO; 
    } 
    

    Custom Action from UICell canPerformAction

+3

W customAction, nadawca jest kontrolerem UIMenuController. W jaki sposób uzyskuje się odniesienie do komórki? – drhr

+0

@drhr znalazłeś rozwiązanie dla niego? – Dejell

+0

@Odelya Myślę, że możesz użyć tej metody do przechowywania ostatniej komórki, która zażądała akcji. - (BOOL) collectionView: (UICollectionView *) collectionView shouldShowMenuForItemAtIndexPath: (NSIndexPath *) indexPath Możesz pobrać tam indeks IndexPath. –

5

Może trochę późno, ale może znaleźć lepsze rozwiązanie dla tych, którzy są jeszcze poszukać:

W viewDidLoad swojej UICollectionViewController Dodaj swoją pozycję:

UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Title" action:@selector(action:)]; 
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObject:menuItem]]; 

Dodaj następujące metody delegatów:

//This method is called instead of canPerformAction for each action (copy, cut and paste too) 
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 
     if (action == @selector(action:)) { 
      return YES; 
     } 
     return NO; 
    } 
    //Yes for showing menu in general 
    - (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath { 
     return YES; 
    } 

Podklasa UICollectionViewCell, jeśli jeszcze tego nie zrobiłeś. Dodaj metodę wybraną dla swojego przedmiotu:

- (void)action:(UIMenuController*)menuController { 

} 

W ten sposób nie potrzebujesz żadnej metody FirstResponder ani innych metod. Masz wszystkie działania w jednym miejscu i możesz łatwo obsługiwać różne komórki, jeśli wywołasz ogólną metodę z samą komórką jako parametrem.

Edit: Jakoś uicollectionview wymaga istnienia tej metody (metoda ta jest wywoływana dla niestandardowego działania, myślę, że uicollectionview prostu sprawdza istnienia)

- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 

} 
+0

Dziękujemy za edytowanie! – Nilz11

+0

@ThinkBonobo Dzięki za komentarz, ale tak naprawdę to była moja edycja, po prostu poprawił angielski ;-). – Nilz11

+0

Ta odpowiedź była szczególnie pomocna.Jednak nadal musiałem w końcu utworzyć delegata, który odesłał do kontrolera kolekcji, aby móc odświeżyć kontroler kolekcji. Zwróć też uwagę na edycję. ta pusta klasa performAction jest potrzebna. – ThinkBonobo

Powiązane problemy