8

各セルに UIImageView を含む UICollectionView があり、Photos.app のように Copy Callout を追加したいと思います。

ここに画像の説明を入力

UICollectionViewDelegate でこのメソッドを見ました。

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

さらに数分間の調査の後、UIMenuController クラスを見つけました。私が理解したように、メニューを取得するにはそれを操作する必要がありますが、とにかく、UIGestureRecognizer を作成し、作成、配置などを行うよりも簡単な方法が必要だと思います。 UIMenu.

私は正しい軌道に乗っていますか?この機能をどのように実装できますか?

4

3 に答える 3

18

はい、あなたは正しい軌道に乗っています。この手法を使用して、切り取り、コピー、貼り付け以外のカスタム アクションを実装することもできます。

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. デリゲート プロトコルを作成し、それをすべてのセルに設定して、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 のカスタム長押しアクション メニュー

  4. オプション: UIView サブクラスでは、メソッド canPerformAction を UIViewController ではなくここに実装すると、デフォルトのカット、コピー、ペーストをオーバーライドできます。そうしないと、カスタム メソッドの前に既定のメソッドが表示されます。

    // 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 からのカスタム アクション

于 2012-11-29T03:12:25.877 に答える
10

これは完全な解決策です:

- (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 でコピー機能のみを許可しており、コピーが押された場合は、セル内の画像を PasteBoard にコピーしています。

于 2012-11-19T17:33:03.333 に答える