Измените местоположение UImenu в swift

#ios #swift #uikit #uimenu

Вопрос:

Я хочу добавить UIMenu в свое приложение, я практиковался с ним, и теперь у меня возник вопрос, можно ли установить местоположение UIMenu немного выше, чем кнопка, которая в данный момент отображает его:

Меню над кнопкой

как вы можете видеть на этой фотографии, меню в настоящее время накладывается на панель вкладок, и я хотел установить его немного выше, чем панель вкладок. вот мой код:

 let menu = UIMenu(title: "", children: [
  UIAction(title: NSLocalizedString("Gallery", comment: ""), image: UIImage(systemName: "folder"), handler: {
    (_) in
    self.loadPhotoGallery()
  })
])

btnMenuExtras.menu = menu
 

Комментарии:

1. Возможно ли, что мы можем предоставить относительное смещение x/y или абсолютное положение экрана x/y для отображения UIMenu?

2. @CheokYanCheng, вероятно, невозможно, если вы не клонируете его — проверьте github.com/christianselig/ChidoriMenu

Ответ №1:

iOS 14

В Sinse iOS 14 UIControl есть метод, который предоставляет точку, к которой прикрепляется меню

 /// Return a point in this control's coordinate space to which to attach the given configuration's menu.
@available(iOS 14.0, *)
open func menuAttachmentPoint(for configuration: UIContextMenuConfiguration) -> CGPoint
 

таким образом, вы можете переопределить UIButton , чтобы указать желаемое расположение меню (вычисленное или жестко закодированное) относительно самой кнопки (потому что она находится в координатном пространстве кнопки), и использовать эту кнопку либо в раскадровке (как класс для управления), либо создать программно (если вам нужно куда-то ее вставить).:

 class MyButton: UIButton {
    var offset = CGPoint.zero
    override func menuAttachmentPoint(for configuration: UIContextMenuConfiguration) -> CGPoint {
        // hardcoded variant
//      return CGPoint(x: 0, y: -50)

        // or relative to orginal
        let original = super.menuAttachmentPoint(for: configuration)
        return CGPoint(x: original.x   offset.x, y: original.y   offset.y)
    }
}

class ViewController: UIViewController {

    @IBOutlet weak var btnMenuExtras: MyButton!   // << from storyboard

    override func viewDidLoad() {
        super.viewDidLoad()

        let menu = UIMenu(title: "", children: [
            UIAction(title: NSLocalizedString("Gallery", comment: ""), image: UIImage(systemName: "folder"), handler: {
                (_) in
//              self.loadPhotoGallery()
            })
        ])

        // offset is hardcoded for demo simplicity
        btnMenuExtras.offset = CGPoint(x: 0, y: -50)    // << here !!
        btnMenuExtras.menu = menu
    }
}
 

ДЕМОНСТРАЦИЯ

Результат:

демонстрация1

Демо подготовлено и протестировано с помощью Xcode 13 / iOS 15

Комментарии:

1. Спасибо за ценный вклад. Однако для кнопки на панели инструментов мы обычно используем UIBarButtonItem то, что не наследуется UIControl . (Я обнаружил, что можно добавить UIButton в UIToolbar. Но я не уверен, каков возможный побочный эффект использования UIButton в отличие от UIBarButtonItem)

2. ОК. Я выясняю, в чем заключается нежелательный побочный эффект использования UIButton в отличие от UIBarButtonItem . Использование UIButton вместо UIBarButtonItem , приведет к проблеме с размером элементов панели инструментов.

Ответ №2:

Вы можете использовать метод menuAttachmentPoint UIControl для UIButton, чтобы найти меню и преобразовать его в UIBarButtonItem С помощью расширения ниже

 @available(iOS 14.0, *)
open func menuAttachmentPoint(for configuration: UIContextMenuConfiguration) -> CGPoint

extension UIButton {
  func toBarButtonItem() -> UIBarButtonItem? {
     return UIBarButtonItem(customView: self)
  }
}
 

Комментарии:

1. Спасибо. Возможность обернуть UIButton вокруг UIBarButtonItem-полезная техника.

Ответ №3:

Я хотел бы расширить ответ @Asperi и @Jayesh Patel о том, как мы можем применить эту технику на UIBarButtonItem

 //
// Technique provided by @Asperi
//
class MyButton: UIButton {
    var offset = CGPoint.zero
    override func menuAttachmentPoint(for configuration: UIContextMenuConfiguration) -> CGPoint {
        // hardcoded variant
//      return CGPoint(x: 0, y: -50)

        // or relative to orginal
        let original = super.menuAttachmentPoint(for: configuration)
        return CGPoint(x: original.x   offset.x, y: original.y   offset.y)
    }
}

let image = UIImage(systemName: "ellipsis.circle", withConfiguration: UIImage.SymbolConfiguration(scale: .default))
let button = MyButton()
button.setImage(image, for: .normal)

let menu = UIMenu(title: "", children: [
    UIAction(title: NSLocalizedString("Gallery", comment: ""), image: UIImage(systemName: "folder"), handler: {
        (_) in
    })
])
// offset is hardcoded for demo simplicity
button.offset = CGPoint(x: 0, y: 50)    // << here !!

//
// This is how we can make UIButton as UIBarButtonItem
//
button.menu = menu
button.showsMenuAsPrimaryAction = true

//
// Technique provided by @Jayesh Patel
//
let threeDotsBarButtonItem = UIBarButtonItem(customView: button)
var items = toolbar.items
items?.append(threeDotsBarButtonItem)
toolbar.items = items