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

SwiftUI中contextMenu与RoundedRectangle结合的长按圆角异常解决

解决SwiftUI长按contextMenu时圆角异常问题

问题分析

在iOS18.2中,给自定义圆角的视图添加contextMenu后,长按触发动画过程中会出现直角高亮的异常——这是因为系统默认的contextMenu高亮层不会继承视图的圆角设置,仅靠clipShape/contentShape无法影响这个临时生成的高亮层。

解决方案1:使用.buttonBorderShape指定高亮形状

这是代码改动最小的修复方式,通过添加.buttonBorderShape强制高亮层使用自定义圆角:

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene { WindowGroup { TestView() } }
}

struct TestView: View {
    let items = ["Item 1", "Item 2", "Item 3"]
    var body: some View {
        VStack {
            ForEach(items, id: \.self) { item in
                HStack {
                    Text(item)
                    Spacer()
                    Image(systemName: "star")
                }
                .padding()
                .background(.yellow)
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .contentShape(RoundedRectangle(cornerRadius: 10))
                .buttonBorderShape(.roundedRectangle(radius: 10)) // 指定高亮层的圆角形状
                .contextMenu {
                    Button { print("Edit \(item)") }
                    label: { Text("Edit"); Image(systemName: "pencil") }
                }
            }
        }
        .padding()
    }
}

#Preview { TestView() }

解决方案2:自定义长按手势控制contextMenu

如果方案1无效,可以通过手动处理长按手势绕过系统默认高亮动画,完全自定义交互逻辑:

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene { WindowGroup { TestView() } }
}

struct TestView: View {
    let items = ["Item 1", "Item 2", "Item 3"]
    @State private var showingMenu = false
    @State private var currentItem: String?
    @State private var menuAnchor: UnitPoint = .center
    
    var body: some View {
        VStack {
            ForEach(items, id: \.self) { item in
                HStack {
                    Text(item)
                    Spacer()
                    Image(systemName: "star")
                }
                .padding()
                .background(.yellow)
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .contentShape(RoundedRectangle(cornerRadius: 10))
                // 自定义长按手势触发菜单
                .highPriorityGesture(LongPressGesture().onEnded { _ in
                    currentItem = item
                    showingMenu = true
                })
                // 手动绑定菜单显示状态
                .contextMenu(isPresented: $showingMenu, anchor: menuAnchor) {
                    if let item = currentItem {
                        Button { 
                            print("Edit \(item)")
                            showingMenu = false
                        } label: { 
                            Text("Edit")
                            Image(systemName: "pencil") 
                        }
                    }
                }
                // 计算菜单锚点,确保显示位置正确
                .background(GeometryReader { geo in
                    Color.clear.onAppear {
                        let globalFrame = geo.frame(in: .global)
                        menuAnchor = UnitPoint(
                            x: globalFrame.midX / UIScreen.main.bounds.width,
                            y: globalFrame.midY / UIScreen.main.bounds.height
                        )
                    }
                })
            }
        }
        .padding()
    }
}

#Preview { TestView() }

关键说明

  • 方案1优先尝试,仅需添加一行代码即可让系统高亮层匹配自定义圆角。
  • 方案2适合需要更灵活交互的场景,完全接管菜单触发逻辑,避免系统默认动画干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:48:12