You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将UIMenu自定义为横向布局并实现图标下显示文字?

实现横向图标+下方文字的自定义菜单

可以实现iOS备忘录那种横向排列、图标下方带文字的菜单效果,本质是通过自定义popover弹窗而非系统默认UIMenu样式来实现,具体步骤如下:

步骤1:封装图标+下方文字的按钮组件

先做一个可复用的按钮,配置图标在上、文字在下的布局:

func createMenuButton(image: UIImage?, title: String) -> UIButton {
    var config = UIButton.Configuration.plain()
    config.image = image?.withRenderingMode(.alwaysTemplate)
    config.title = title
    config.imagePlacement = .top
    config.imagePadding = 4
    config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
        var outgoing = incoming
        outgoing.font = UIFont.systemFont(ofSize: 12)
        return outgoing
    }
    
    let button = UIButton(configuration: config)
    button.tintColor = .systemBlue
    button.addTarget(self, action: #selector(menuButtonTapped(_:)), for: .touchUpInside)
    return button
}

@objc func menuButtonTapped(_ sender: UIButton) {
    // 根据按钮标题区分执行对应操作
    switch sender.titleLabel?.text {
    case "扫描":
        // 处理扫描逻辑
        break
    case "固定":
        // 处理固定逻辑
        break
    case "锁定":
        // 处理锁定逻辑
        break
    default:
        break
    }
    // 关闭弹窗
    sender.parentViewController?.dismiss(animated: true)
}

步骤2:构建横向排列的菜单视图

用UIStackView横向组装多个按钮:

func createMenuView() -> UIView {
    let stackView = UIStackView()
    stackView.axis = .horizontal
    stackView.spacing = 24
    stackView.distribution = .equalSpacing
    stackView.alignment = .center
    
    // 添加功能按钮
    let scanBtn = createMenuButton(image: UIImage(systemName: "doc.text.viewfinder"), title: "扫描")
    let pinBtn = createMenuButton(image: UIImage(systemName: "pin"), title: "固定")
    let lockBtn = createMenuButton(image: UIImage(systemName: "lock"), title: "锁定")
    
    stackView.addArrangedSubview(scanBtn)
    stackView.addArrangedSubview(pinBtn)
    stackView.addArrangedSubview(lockBtn)
    
    // 设置内边距优化布局
    stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
    stackView.isLayoutMarginsRelativeArrangement = true
    
    return stackView
}

步骤3:给导航栏按钮绑定弹窗逻辑

创建UIBarButtonItem,点击时弹出自定义popover:

// 初始化导航栏右侧按钮
let menuBarBtn = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), style: .plain, target: self, action: #selector(showCustomMenu))
navigationItem.rightBarButtonItem = menuBarBtn

@objc func showCustomMenu() {
    let menuView = createMenuView()
    
    // 弹窗容器控制器
    let popupVC = UIViewController()
    popupVC.view = menuView
    popupVC.preferredContentSize = menuView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    
    // 配置popover样式
    popupVC.modalPresentationStyle = .popover
    if let popover = popupVC.popoverPresentationController {
        popover.barButtonItem = navigationItem.rightBarButtonItem
        popover.permittedArrowDirections = .up
    }
    
    present(popupVC, animated: true)
}

注意事项

  • UIButton.Configuration是iOS 15+API,若需兼容iOS 14及以下,可通过手动设置按钮的image、title,并添加约束实现图标在上、文字在下的布局。
  • 可根据需求调整按钮的字体、颜色、间距等样式,适配不同设计要求。

内容的提问来源于stack exchange,提问作者shuna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 06:45:29