2012-11-19 8 views
8

ich in jeder Zelle eine UICollectionView mit UIImageView haben, jetzt will ich Callout kopieren, wie in Photos.app hinzuzufügen:Kopieren Callout in UICollectionView

enter image description here

sah ich diese Methode in der UICollectionViewDelegate:

Nach einigen zusätzlichen Minuten der Forschung fand ich UIMenuController Klasse, wie ich verstanden habe, muss ich damit arbeiten, um das Menü zu bekommen, aber trotzdem denke ich, dass es einfacher Weg sein muss, dann UIGestureRecognizer und cre ting, Positionierung usw. mein UIMenu.

Bin ich auf dem richtigen Weg? Wie können Sie diese Funktion implementieren?

Antwort

9

Dies ist die vollständige Lösung:

- (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]; 
     } 
    } 

In meinem Fall, ich bin so dass nur Copy-Funktion in meinem Collection, und wenn die Kopie gedrückt wird, ich bin Kopieren des Bildes, das innerhalb der ist Zelle zum PasteBoard.

+0

Ja, du diese drei Methoden nur brauchen. Alles andere ist unnötig. –

+0

Danke, ich habe versucht, Lösung, während Sie UIMenuItem schreiben * menuItem = [[UIMenuItem alloc] initWithTitle: @ "Bearbeiten" Aktion: @selector (editPlate :)]; Allerdings muss ich eine Methode editPlate haben, aber ich möchte performAction verwenden, damit ich die Zellen-ID kennen kann. Wie finden Sie den Menüpunkt? – Dejell

18

Ja, Sie sind auf dem richtigen Weg. Sie können mit dieser Technik auch benutzerdefinierte Aktionen implementieren, die über das Ausschneiden, Kopieren und Einfügen hinausgehen.

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); 
} 

Hinweis: iOS 7.0 Änderungen des Verhaltens

  1. In Ihrem UICollectionViewCell Unterklasse müssen Sie die benutzerdefinierte Aktion Methoden hinzuzufügen, oder es wird nichts angezeigt.

    // 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. Sie benötigen einen Delegaten Protokoll erstellen und sie auf jede Zelle zurück zum UIController nennen, die Ihre UICollectionView hält. Dies liegt daran, dass die Zelle an Ihrem Modell nichts ändern sollte, da es nur an der Anzeige von Inhalten beteiligt ist.

    // 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. In Ihrem Viewcontroller oder Unterklasse von UICollectionViewController Sie benötigen, um das Protokoll zu entsprechen und die neue Methode zu implementieren.

    // 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. Optional: In Ihrem UIView Subclass Sie den Standard-Cut außer Kraft setzen können, kopieren, einfügen, wenn Sie die Methode canPerformAction hier implementieren, anstatt in dem UIViewController. Andernfalls zeigt das Verhalten die Standardmethoden vor Ihren benutzerdefinierten Methoden an.

    // 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

In CustomAction ist Absender der UIMenuController. Wie bekommst du davon Bezug auf die Zelle? – drhr

+0

@drhr hast du eine Lösung dafür gefunden? – Dejell

+0

@ Odelya Ich denke, dass Sie die Methode verwenden können, um die letzte Zelle zu speichern, die die Aktion angefordert hat. - (BOOL) collectionView: (UICollectionView *) collectionView sollteShowMenuForItemAtIndexPath: (NSIndexPath *) indexPath Sie können den IndexPath dort abrufen. –

5

Vielleicht ein bisschen spät, aber ich fand vielleicht eine bessere Lösung für diejenigen, die für diese nach wie vor suchen sind:

In viewDidLoad Ihrer UICollectionViewController Ihr Element hinzufügen:

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

Fügen Sie die folgenden Delegatmethoden hinzu:

//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; 
    } 

Unterklasse UICollectionViewCell, wenn Sie nicht bereits. Fügen Sie die Methode, die Sie für Ihre Artikel angegeben:

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

} 

Auf diese Weise können keine becomeFirstResponder oder andere Methoden benötigen. Sie haben alle Aktionen an einem Ort und Sie können leicht verschiedene Zellen behandeln, wenn Sie eine allgemeine Methode mit der Zelle selbst als Parameter aufrufen.

Edit: Irgendwie ist der uicollectionview die Existenz dieser Methode muss (diese Methode nicht für die benutzerdefinierte Aktion aufgerufen wird, denke ich, die uicollectionview nur für existance prüft)

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

} 
+0

Vielen Dank für die Bearbeitung! – Nilz11

+0

@ThinkBonobo Danke für deinen Kommentar, aber eigentlich war es mein Schnitt, er hat nur das Englisch verbessert ;-). – Nilz11

+0

Ich fand diese Antwort besonders hilfreich.Allerdings musste ich noch einen Delegaten erstellen, der auf den Sammlungscontroller zurückverwies, damit ich den Sammlungscontroller aktualisieren konnte. Achte auch auf den Schnitt. Diese leere performAction-Klasse wird benötigt. – ThinkBonobo