How can you add a UIGestureRecognizer to a UIBarButtonItem as in the common undo/redo UIPopoverController scheme on iPad apps?

后端 未结 15 1551
被撕碎了的回忆
被撕碎了的回忆 2020-12-07 12:36

Problem

In my iPad app, I cannot attach a popover to a button bar item only after press-and-hold events. But this seems to be standard for

15条回答
  •  感情败类
    2020-12-07 12:56

    I know this is old but I spent a night banging my head against the wall trying to find an acceptable solution. I didn't want to use the customView property because would get rid of all of the built in functionality like button tint, disabled tint, and the long press would be subjected to such a small hit box while UIBarButtonItems spread their hit box out quite a ways. I came up with this solution that I think works really well and is only a slight pain to implement.

    In my case, the first 2 buttons on my bar would go to the same place if long pressed, so I just needed to detect that a press happened before a certain X point. I added the long press gesture recognizer to the UIToolbar (also works if you add it to a UINavigationBar) and then added an extra UIBarButtonItem that's 1 pixel wide right after the 2nd button. When the view loads, I add a UIView that's a single pixel wide to that UIBarButtonItem as it's customView. Now, I can test the point where the long press happened and then see if it's X is less than the X of the customview's frame. Here's a little Swift 3 Code

    @IBOutlet var thinSpacer: UIBarButtonItem!
    
    func viewDidLoad() {
        ...
        let thinView = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 22))
        self.thinSpacer.customView = thinView
    
        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressed(gestureRecognizer:)))
        self.navigationController?.toolbar.addGestureRecognizer(longPress)
        ...
    }
    
    func longPressed(gestureRecognizer: UIGestureRecognizer) {
        guard gestureRecognizer.state == .began, let spacer = self.thinSpacer.customView else { return }
        let point = gestureRecognizer.location(ofTouch: 0, in: gestureRecognizer.view)
        if point.x < spacer.frame.origin.x {
            print("Long Press Success!")
        } else {
            print("Long Pressed Somewhere Else")
        }
    }
    

    Definitely not ideal, but easy enough for my use case. If you need a specify a long press on specific buttons in specific locations, it gets a little more annoying but you should be able to surround the buttons you need to detect the long press on with thin spacers and then just check that your point's X is between both of those spacers.

提交回复
热议问题