在UICollectionView中复制标注

我有一个UICollectionView与UIImageView在每个单元格中,现在我想添加复制标注,就像Photos.app中:

在这里输入图像说明

我在UICollectionViewDelegate中看到了这个方法:

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

经过几分钟的研究,我发现UIMenuController类,据我所知,我必须与它合作得到菜单,但无论如何,我认为必须有更简单的方法,然后创buildUIGestureRecognizer,创build,定位等我UIMenu。

我在正确的轨道上? 你怎么能实现这个function?

是的,你在正确的轨道上。 您还可以使用此技术实现除剪切,复制和粘贴之外的自定义操作。

自定义操作为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); } 

注意:iOS 7.0更改行为

  1. 在你的UICollectionViewCell子类中,你需要添加自定义的动作方法,否则什么都不会出现。

     // 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. 您需要创build一个委托协议,并将其设置在每个单元上,以callback到维护您的UICollectionView的UIController。 这是因为单元格不应该与您的模型有关,因为它只涉及显示内容。

     // 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. 在您的ViewController或UICollectionViewController的子类中,您需要遵守协议并实施新的方法。

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

    用于UICollectionView的自定义longpress操作菜单

  4. 可选 :在你的UIView子类中,如果你在这里实现了方法canPerformAction,而不是在UIViewController中,你可以覆盖默认的Cut,Copy,Paste。 否则,行为将显示您的自定义方法之前的默认方法。

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

    自定义行动从UICell canPerformAction

这是完整的解决scheme:

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

在我的情况下,我只允许我的CollectionView中的复制function,如果复制被按下,我复制在单元格内的图像到PasteBoard。

也许有点晚,但我也许find了一个更好的解决scheme,为那些仍然在寻找这个:

在你的UICollectionViewController的viewDidLoad中添加你的项目:

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

添加下面的委托方法:

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

子类UICollectionViewCell,如果你还没有。 添加您为项目指定的方法:

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

这样,你不需要任何becomeFirstResponder或其他方法。 您可以在一个地方执行所有操作,如果您使用单元格本身作为参数调用常规方法,则可以轻松处理不同的单元格。

编辑:不知何故uicollectionview需要这种方法的存在(这种方法是不是你的自定义操作调用,我认为uicollectionview只是检查存在)

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