Как программно представить меню при однократном касании строки представления таблицы, как в приложении «Календарь» iOS 16?
В приложении «Календарь» iOS 16 появился новый стиль раскрывающегося меню для таких параметров, как «повторить», при нажатии на любое место строки появлялось меню. И в правой части ячейки представления таблицы есть значок шеврона вверх и шеврона вниз.
Как это сделать в iOS 16? Контекстное меню вызывается долгим нажатием, но этот новый стиль — одним нажатием.
4 ответа
Вы можете добавить UIButton в TableViewCell и заполнить все пространство. Используйте свойство меню UIButton для достижения эффекта системного календаря.
button.menu = menu
Вы можете проверить код, который я написал, надеюсь, он вам поможет. https://github.com/zhi6w/TableViewCellWithMenuButton
Вопрос в том, какое всплывающее меню используется в приложении «Календарь». Кнопка представляет собой всплывающую кнопку . В UIKit это реализовано с помощьюUIButton
. Вам нужно настроить кнопкуmenu
и установитеshowsMenuAsPrimaryAction
иchangesSelectionAsPrimaryAction
свойства дляtrue
.
Вот пример кода для создания такой кнопки и применения ее к ячейке таблицы:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ... // Create and setup your cell as needed
// Create the popup button
let cfg = UIButton.Configuration.plain()
let button = UIButton(configuration: cfg)
// Replace the following with your own code to support your own menu.
// The important part here is that zero or one actions is set with a
// state of on and the rest are set to off. This defines the initially
// selected value, if any. The state of the actions are updated as the
// user makes a selection.
button.menu = UIMenu(options: [.singleSelection], children: [
UIAction(title: "Option 1", state: self.option == .option1 ? .on : .off, handler: { [weak self] action in
self?.option = .option1
}),
UIAction(title: "Option 2", state: self.option == .option2 ? .on : .off, handler: { [weak self] action in
self?.option = .option2
}),
])
// After setting the menu, the following two properties signify that
// the button is to look and act like a popup button. This includes
// the up/down arrows on the right side of the button which is shown
// by default for a popup button.
button.showsMenuAsPrimaryAction = true
button.changesSelectionAsPrimaryAction = true
// This puts the button on the right end of the cell.
cell.accessoryView = button
return cell
}
Код меню, показанный выше, предполагает наличие некоторыхenum
представляющие различные выбираемые опции и что существуетoption
свойство для отслеживания выбранной опции. Существует много возможных способов и вариантов использования меню, поэтому я оставляю это на усмотрение вашего приложения. Важная часть этого ответа показывает базовую настройку, необходимую для репликации всплывающей кнопки, используемой в приложении «Календарь».
Начиная с iOS 16, вы можете сделать это, хотя и с помощью горизонтально расположенного меню редактирования или, альтернативно, с помощью жеста длительного нажатия, чего пользователь не может ожидать.
В первом случае вы предоставляете UIMenu методу делегата меню редактирования, а во втором вы используете меню делегата контекстного меню. Для горизонтального меню, чем короче имена меню, тем лучше, особенно если у вас более 2 или 3 элементов, чтобы пользователю не приходилось щелкать правый треугольник в конце, чтобы отобразить больше элементов.
Методы делегата соответственно возвращают UIMenu, который вы можете создать прямо в методе делегата, или вы можете настроить его для повторного использования вызванного упоминания, возможно, с помощью всплывающего окна UIButton() внутри ячейки tableView, так вы поправитесь. покрытие на случай, если пользователь не нажмет саму кнопку.
Способ 1: Пользовательское меню редактирования (например, существующее горизонтальное меню):
var editMenuInteraction : UIEditMenuInteraction! = nil
override func viewDidLoad() {
editMenuInteraction = UIEditMenuInteraction(delegate: self)
}
extension MyViewController: UIEditMenuInteractionDelegate {
func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
let myAction = UIAction(title: "Action1", image: UIImage(systemName: "bell"), identifier: nil) { action in
print("MyAction tapped")
}
let anotherAction = UIAction(title: "Action2", image: UIImage(systemName: "person"), identifier: nil) { action in
print("AnotherAction tapped")
}
.
.
.
return UIMenu(title: "", children: [myAction, anotherAction])
}
}
extension MyViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.addInteraction(editMenuInteraction)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let interaction = editMenuInteraction {
let rect = tableView.rectForRow(at: indexPath)
let absoluteRect = tableView.convert(rect, to: tableView.superview)
let configuration = UIEditMenuConfiguration(identifier: nil, sourcePoint: absoluteRect.origin)
interaction.presentEditMenu(with: configuration)
}
}
}
Способ 2: контекстное меню (например, долгое нажатие на ячейку)
// In your cellForRowAt tableView delegate method:
let interaction = UIContextMenuInteraction(delegate: self)
cell?.addInteraction(interaction)
extension MyViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions in
let myAction = UIAction(title: "MyAction", image: UIImage(systemName: "bell"), identifier: nil) { action in
print("MyAction tapped")
}
let anotherAction = UIAction(title: "AnotherAction", image: UIImage(systemName: "person"), identifier: nil) { action in
print("AnotherAction tapped")
}
.
.
.
return UIMenu(title: "", children: [myAction, anotherAction])
}
}
}
Вы можете добавить меню отображения UIButton в contentView tableViewCell.
class TestCell: UITableViewCell {
lazy var menuButton: UIButton = {
let button = UIButton()
button.showsMenuAsPrimaryAction = true
// custom your menu
button.menu = UIMenu(title: "menus", children: [])
return button
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier)
contentView.addSubview(menuButton)
}
}