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

Swift如何移除UIContextMenu消失动画中显示的阴影

UIContextMenu阴影残留解决方案

全局移除所有UIContextMenu阴影

UIContextMenu的默认阴影全部附着在私有类UIPreviewContainerView的图层上,你可以通过方法交换全局修改该类实例的阴影属性:

import UIKit

private func swizzleMethod(for clazz: AnyClass, originalSel: Selector, swizzledSel: Selector) {
    guard let originalMethod = class_getInstanceMethod(clazz, originalSel),
          let swizzledMethod = class_getInstanceMethod(clazz, swizzledSel) else { return }
    method_exchangeImplementations(originalMethod, swizzledMethod)
}

extension UIView {
    /// 全局关闭UIContextMenu阴影,建议在App启动时调用一次
    static func disableGlobalContextMenuShadow() {
        guard let previewContainerCls = NSClassFromString("UIPreviewContainerView") as? UIView.Type else { return }
        swizzleMethod(for: previewContainerCls, 
                      originalSel: #selector(didMoveToWindow), 
                      swizzledSel: #selector(ss_disableShadow_didMoveToWindow))
    }
    
    @objc private func ss_disableShadow_didMoveToWindow() {
        ss_disableShadow_didMoveToWindow()
        // 清除当前视图阴影
        layer.shadowOpacity = 0
        layer.shadowRadius = 0
        // 清除所有子视图阴影
        subviews.forEach { subview in
            subview.layer.shadowOpacity = 0
            subview.layer.shadowRadius = 0
        }
    }
}

你只需要在AppDelegate的didFinishLaunchingWithOptions方法中调用UIView.disableGlobalContextMenuShadow()即可全局生效,不会影响其他控件的阴影效果。

单页面/单菜单禁用阴影

如果不需要全局修改,可以自定义上下文菜单的预览视图,直接关闭预览阴影:

func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
    let config = UIContextMenuConfiguration(identifier: indexPath as NSCopying, previewProvider: { [weak self] in
        guard let self = self, let cell = self.tableView.cellForRow(at: indexPath) else { return nil }
        // 复制cell内容作为预览
        let previewView = cell.snapshotView(afterScreenUpdates: false)
        let previewVC = UIViewController()
        previewVC.view = previewView
        previewVC.view.layer.shadowOpacity = 0
        previewVC.preferredContentSize = cell.bounds.size
        return previewVC
    }, actionProvider: { _ in
        // 你的菜单操作配置
        return UIMenu(title: "", children: [])
    })
    return config
}

如果还是有退场阴影残留,可以额外实现两个预览代理方法,完全接管入场退场的预览效果:

// 高亮预览
func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
    guard let indexPath = configuration.identifier as? IndexPath, let cell = tableView.cellForRow(at: indexPath) else { return nil }
    let parameters = UIPreviewParameters()
    parameters.backgroundColor = .clear
    parameters.shadowPath = nil // 强制关闭阴影
    return UITargetedPreview(view: cell, parameters: parameters)
}

// 退场预览
func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
    return self.tableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 20:54:03