6

长按 UICollectionViewCell 时,我添加了自定义菜单控制器

    [self becomeFirstResponder];
    UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Custom Action"
                                                      action:@selector(customAction:)];
    [[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObject:menuItem]];
    [[UIMenuController sharedMenuController] setTargetRect: self.frame inView:self.superview];
    [[UIMenuController sharedMenuController] setMenuVisible:YES animated: YES];

canBecomeFirstResponder 也被调用

- (BOOL)canBecomeFirstResponder {
    // NOTE: This menu item will not show if this is not YES!
    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;
}

我也实现了这些方法

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


    if([NSStringFromSelector(action) isEqualToString:@"customAction:"]){
        NSLog(@"indexpath : %@",indexPath);
        UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:@"warning.." message:@"Do you really want to delete this photo?" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
        [alertview show];
        return YES;
    }

    return YES;

}

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

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

虽然它只显示“剪切、复制和粘贴”菜单

4

6 回答 6

8

也许有点晚了,但我可能为那些仍在寻找这个的人找到了一个更好的解决方案:

在 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 {

}
于 2013-09-10T17:28:35.067 回答
6

您需要从自定义 UICollectionViewCell 触发委托函数

这是我的 Swift3 工作示例代码

集合视图控制器

override func viewDidLoad() {
    super.viewDidLoad()
    let editMenuItem = UIMenuItem(title: "Edit", action: NSSelectorFromString("editCollection"))
    let deleteMenuItem = UIMenuItem(title: "Delete", action: NSSelectorFromString("deleteCollection"))
    UIMenuController.shared.menuItems = [editMenuItem, deleteMenuItem]

}

override func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
    return true
}

override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
    return action == NSSelectorFromString("editCollection") || action == NSSelectorFromString("deleteCollection")
}

override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
    print("action:\(action.description)")
    //Custom actions here..
}

将以下函数添加到您的自定义 UICollectionViewCell

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == NSSelectorFromString("editCollection") || action == NSSelectorFromString("deleteCollection")
}

从单元格调用委托函数(需要在您的自定义 UICollectionViewCell 中)

func editCollection()
{
    let collectionView = self.superview as! UICollectionView
    let d:UICollectionViewDelegate = collectionView.delegate!
    d.collectionView!(collectionView, performAction: NSSelectorFromString("editCollection"), forItemAt: collectionView.indexPath(for: self)!, withSender: self)
}
func deleteCollection()
{
    let collectionView = self.superview as! UICollectionView
    let d:UICollectionViewDelegate = collectionView.delegate!
    d.collectionView!(collectionView, performAction: NSSelectorFromString("deleteCollection"), forItemAt: collectionView.indexPath(for: self)!, withSender: self)
}
于 2016-10-10T10:59:23.910 回答
4

我刚刚花了两天时间试图找出“正确”的做法,并用周围的一些建议找出错误的树。

本文显示了执行此操作的正确方法。我希望通过在这里发布它可以节省几个小时。

http://dev.glide.me/2013/05/custom-item-in-uimenucontroller-of.html

于 2013-08-28T00:33:30.877 回答
2

斯威夫特 3 解决方案:

只需在 UICollectionView 类中执行所有操作并将此类分配给 UICollectionView 对象。

import UIKit

class MyAppCollectionView: UICollectionView {

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        addLongPressGesture()
    }

    func addLongPressGesture() {
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(MyAppCollectionView.longPressed(_:)))
        longPressGesture.minimumPressDuration = 0.5
        self.addGestureRecognizer(longPressGesture)
    }

    func longPressed(_ gesture: UILongPressGestureRecognizer) {

        let point = gesture.location(in: self)
        let indexPath = self.indexPathForItem(at: point)

        if indexPath != nil {

            MyAppViewController.cellIndex = indexPath!.row
            let editMenu = UIMenuController.shared
            becomeFirstResponder()
            let custom1Item = UIMenuItem(title: "Custom1", action: #selector(MyAppViewController.custome1Method))
            let custom2Item = UIMenuItem(title: "Custom2", action: #selector(MyAppViewController.custome2Method))
            editMenu.menuItems = [custom1Item, custom2Item]
            editMenu.setTargetRect(CGRect(x: point.x, y: point.y, width: 20, height: 20), in: self)
            editMenu.setMenuVisible(true, animated: true)
        }

    }

    override var canBecomeFirstResponder: Bool {

        return true
    }
}

class MyAppViewController: UIViewController {

     override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
            // You need to only return true for the actions you want, otherwise you get the whole range of
            //  iOS actions. You can see this by just removing the if statement here.

            //For folder edit
            if action == #selector(MyAppViewController.custome1Method) {
                return true
            }

            if action == #selector(MyAppViewController.custome2Method) {
                return true
            }

            return false
        }
}
于 2017-02-25T18:47:22.180 回答
1

当人们无法让菜单在集合视图(或表格视图,就此而言)中长按时工作时,总是出于以下两个原因之一:

  • 您正在使用长按手势识别器进行某些操作。例如,您不能在同一个集合视图中同时拥有拖动和菜单。

  • 您忘记在单元格中实现选择器。

例如,OP 的代码说:

UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Custom Action"
                                           action:@selector(customAction:)];

言外之意就是这个customAction类是一个方法。这是错误的。必须是单元类的方法。原因是运行时会查看单元格类并且不会显示菜单项,除非单元格实现了菜单项的操作方法。customAction:

有关完整的最小工作示例(在 Swift 中),请在此处查看我的答案:https ://stackoverflow.com/a/51898182/341994

于 2018-08-17T15:15:32.110 回答
0

在带有Swift的iOS 9上,只显示自定义项目(没有默认的剪切、粘贴等),我只设法使用以下代码。

方法viewDidLoad

let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(contextMenuHandler))
longPressRecognizer.minimumPressDuration = 0.3
longPressRecognizer.delaysTouchesBegan = true
self.collectionView?.addGestureRecognizer(longPressRecognizer)

覆盖方法canBecomeFirstResponder

override func canBecomeFirstResponder() -> Bool {
    return true
}

覆盖这两个与集合相关的方法:

override func collectionView(collectionView: UICollectionView, shouldShowMenuForItemAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

override func collectionView(collectionView: UICollectionView, canPerformAction action: Selector,
                             forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool {
    return (action == #selector(send) || action == #selector(delete))
}

创建手势处理方法:

func contextMenuHandler(gesture: UILongPressGestureRecognizer) {

    if gesture.state == UIGestureRecognizerState.Began {

        let indexPath = self.collectionView?.indexPathForItemAtPoint(gesture.locationInView(self.collectionView))

        if indexPath != nil {

            self.selectedIndexPath = indexPath!

            let cell = self.collectionView?.cellForItemAtIndexPath(self.selectedIndexPath)
            let menu = UIMenuController.sharedMenuController()
            let sendMenuItem = UIMenuItem(title: "Send", action: #selector(send))
            let deleteMenuItem = UIMenuItem(title: "Delete", action: #selector(delete))
            menu.setTargetRect(CGRectMake(0, 5, 60, 80), inView: (cell?.contentView)!)
            menu.menuItems = [sendMenuItem, deleteMenuItem]
            menu.setMenuVisible(true, animated: true)
        }
    }
}

最后,创建选择器的方法:

func send() {
    print("Send performed!")
}

func delete() {
    print("Delete performed!")
}

希望有帮助。:)

干杯。

于 2016-07-06T14:06:31.297 回答