2012-11-19 13 views
8

Ho un UICollectionView con UIImageView in ogni cella, ora voglio aggiungere Copia didascalia, come in Photos.app:Copia didascalia in UICollectionView

enter image description here

Ho visto questo metodo nel UICollectionViewDelegate:

Dopo alcuni minuti di ricerca ho trovato UIMenuController Class, come ho capito, devo lavorare con esso per ottenere il Menu, ma comunque, penso che ci deve essere un modo più semplice per creare UIGestureRecognizer, e cre in corso, posizionando ecc. il mio UIMenu.

Sono sulla buona strada? Come hai potuto implementare questa funzione?

risposta

9

Questa è la soluzione completa:

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

Nel mio caso, io sto consentendo solo funzione Copia nel mio CollectionView, e se si preme la copia, che sto copiando l'immagine che si trova all'interno del cella al PasteBoard.

+0

Sì è solo bisogno di questi 3 metodi. Qualsiasi altra cosa non è necessaria. –

+0

Grazie, ho provato la soluzione, mentre scrivevo UIMenuItem * menuItem = [[UIMenuItem alloc] initWithTitle: @ "Modifica" azione: @selector (editPlate :)]; tuttavia, mi richiede di avere un metodo editPlate ma mi piacerebbe usare performAction, così posso conoscere l'id della cella. Come trovi la voce del menu? – Dejell

18

Sì, sei sulla buona strada. Puoi anche implementare azioni personalizzate oltre a tagliare, copiare, incollare usando questa tecnica.

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

Nota: iOS 7.0 cambiamenti di comportamento

  1. nella sottoclasse UICollectionViewCell è necessario aggiungere i metodi di azione personalizzati, o apparirà nulla.

    // 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. Avrai bisogno di creare un protocollo delegato e impostarlo su ogni cellula di richiamare alla UIController che mantiene il vostro UICollectionView. Questo perché la cella non dovrebbe fare nulla sul tuo modello, poiché è solo coinvolto nella visualizzazione del contenuto.

    // 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. Nella tua ViewController o una sottoclasse di UICollectionViewController è necessario conformarsi al protocollo e implementare il nuovo metodo.

    // 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. opzionale: Nella tua UIView sottoclasse è possibile ignorare il taglio di default, copiare, incollare se si implementa il metodo canPerformAction qui, piuttosto che nel UIViewController. In caso contrario, il comportamento mostrerà i metodi predefiniti prima dei metodi personalizzati.

    // 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, il mittente è UIMenuController. Come si ottiene il riferimento alla cella da quello? – drhr

+0

@drhr hai trovato una soluzione per questo? – Dejell

+0

@Odelya Penso che tu possa usare il metodo per memorizzare l'ultima cella che ha richiesto l'azione. - (BOOL) CollectionView: (UICollectionView *) CollectionView shouldShowMenuForItemAtIndexPath: (NSIndexPath *) indexPath È possibile ottenere l'indexPath lì. –

5

Forse un po 'tardi, ma ho forse trovato una soluzione migliore per coloro che sono ancora in cerca di questo:

In viewDidLoad del vostro UICollectionViewController Aggiungi la tua voce:

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

Aggiungere i seguenti metodi delegato:

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

Sottoclasse UICollectionViewCell se non l'hai già fatto. Aggiungere il metodo specificato per il vostro articolo:

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

} 

In questo modo non è necessario alcun becomeFirstResponder o altri metodi. Hai tutte le azioni in un posto e puoi gestire facilmente celle diverse se chiami un metodo generale con la cella stessa come parametro.

Edit: In qualche modo l'uicollectionview ha bisogno l'esistenza di questo metodo (questo metodo non viene chiamato per l'azione personalizzata, penso che l'uicollectionview solo verifica la presenza di esistenza)

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

} 
+0

Grazie per l'editing! – Nilz11

+0

@ThinkBonobo Grazie per il tuo commento ma in realtà era la mia modifica, ha appena migliorato l'inglese ;-). – Nilz11

+0

Ho trovato questa risposta particolarmente utile.Tuttavia, dovevo ancora creare un delegato che facesse riferimento al controller di raccolta in modo da poter aggiornare il controller di raccolta. Inoltre, prestare attenzione alla modifica. è necessaria la classe empty performAction. – ThinkBonobo

Problemi correlati