ios 当长按子视图时,contextMenu不应用于子视图,而是应用于父视图

cbjzeqam  于 2023-08-08  发布在  iOS
关注(0)|答案(1)|浏览(138)

我想要的

我在做一个组件。此组件用于显示标记列表。我想一个上下文菜单上弹出的标签时,用户长按它。就像这样:


的数据

我得到了什么



您可以看到,上下文菜单显示在标记的容器上,而不是标记上。

我的代码

import SwiftUI
import CoreData

struct AddVision: View {
    @State private var visionTitle: String = ""
    
    var body: some View {
        GeometryReader { geometry in
            NavigationView {
                Form {
                    Section(header: Text("Basic Information")) {
                        TextField("Input Vision Title Please", text: $visionTitle)
                    }
                    Section(header: Text("Tags")) {
                        TagsView(screenWidth: geometry.size.width)
                    }
                }
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button {
                            addNewVision()
                        } label: {
                            Text("Add")
                        }

                    }
                }
            }
        }
    }
    
    private func addNewVision() {
        print("add new vision")
    }
}

struct TagsView: View {
    @Environment(\.managedObjectContext) private var viewContext
    
    // 标签行数组,每一个元素表示一行标签
    @State private var groupedItems: [[Tag]] = [[Tag]]()
    
    // 新标签标题
    @State private var newTagTitle = ""
    
    // 显示标签添加输入框
    @State private var showNewTagInputField = false
    
    // 显示菜单
    @State private var showContextMenu = false
    
    // 显示警告
    @State private var showingAlert = false
    
    // 聚焦
    @FocusState private var keyboardFocused: Bool
    
    // 屏幕宽度
    let screenWidth: CGFloat
    
    init(screenWidth: CGFloat) {
        self.screenWidth = screenWidth
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            ForEach(groupedItems, id: \.self) { itms in
                HStack {
                    ForEach(itms, id: \.self) { tag in
                        Text(tag.title ?? "")
                            .font(.callout)
                            .foregroundColor(/*@START_MENU_TOKEN@*/Color(hue: 0.364, saturation: 0.939, brightness: 0.628)/*@END_MENU_TOKEN@*/)
                            .padding()
                            .frame(height: /*@START_MENU_TOKEN@*/24.0/*@END_MENU_TOKEN@*/)
                            .background(Color(hue: 0.387, saturation: 0.969, brightness: 0.965, opacity: 0.207))
                            .frame(alignment: .center)
                            .cornerRadius(100)
                            .contextMenu {
                                Button {
                                    deleteTheTag(tag)
                                } label: {
                                    Label("Delete", systemImage: "trash")
                                }

                            }
                    }
                }
            }
            
            HStack {
                if showNewTagInputField {
                    TextField("my tag", text: $newTagTitle, onCommit: addTag)
                        .font(.callout)
                        .foregroundColor(/*@START_MENU_TOKEN@*/Color(hue: 0.364, saturation: 0.939, brightness: 0.628)/*@END_MENU_TOKEN@*/)
                        .padding()
                        .frame(height: /*@START_MENU_TOKEN@*/24.0/*@END_MENU_TOKEN@*/)
                        .background(Color(hue: 0.387, saturation: 0.969, brightness: 0.965, opacity: 0.207))
                        .frame(alignment: .center)
                        .cornerRadius(100)
                        .focused($keyboardFocused)
                        .onAppear {
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                                keyboardFocused = true
                            }
                        }
                }
                
                Button {
                    showNewTagInputField = true
                } label: {
                    Image(systemName: "plus")
                }
                .foregroundColor(.white)
                .padding()
                .background(Color(hue: 1.0, saturation: 0.035, brightness: 0.053, opacity: 0.243))
                .frame(height: /*@START_MENU_TOKEN@*/24.0/*@END_MENU_TOKEN@*/)
                .frame(alignment: .center)
                .cornerRadius(100)
            }
            .animation(.easeOut, value: showNewTagInputField)
        }
        .onAppear {
            buildTagGroupList()
        }
    }
    
    private func deleteTheTag(_ tag: Tag) {
        // 删除标签
        viewContext.delete(tag)
        
        // 刷新标签列表
        buildTagGroupList()
    }
    
    private func buildTagGroupList() {
        // 待处理的标签
        var tags = [Tag]()
        
        // 查询标签
        let fetchRequest = NSFetchRequest<Tag>(entityName: "Tag")
        fetchRequest.sortDescriptors = []
        do {
            let results = try viewContext.fetch(fetchRequest)
            for result in results {
                tags.append(result)
            }
        } catch {
            print("查询标签的时候出现错误")
        }
        
        var groupedItems: [[Tag]] = [[Tag]]()
        
        // 一行tag已经占据的宽度
        var width: CGFloat = 0
        
        // 临时存储一行的元素
        var tempItems = [Tag]()
        
        // 循环取出的标签
        for word in tags {
            // 新建一个Label组件
            let label = UILabel()
            
            // 设置Label的内容
            label.text = word.title
            
            // 设置label根据里面text的长度改变其宽度
            label.sizeToFit()
            
            // label的宽度,一个label两边都16点的padding,所以一个label的宽度需要加上32
            let labelWidth = label.frame.size.width + 32
            
            if (width + labelWidth + 32) < screenWidth {
                width += labelWidth
                tempItems.append(word)
            } else {
                width = labelWidth
                groupedItems.append(tempItems)
                tempItems.removeAll()
                tempItems.append(word)
            }
        }
        
        groupedItems.append(tempItems)
        
        self.groupedItems = groupedItems
    }
    
    private func addTag() {
        // 检查是否输入内容
        if self.newTagTitle.isEmpty {
            // 关闭新标签添加输入框
            showNewTagInputField = false
            return
        }
        
        // 向数据库中添加一个标签
        let tag = Tag(context: viewContext)
        tag.id = UUID()
        tag.title = self.newTagTitle
        do {
            try viewContext.save()
        } catch {
            print("保存新标签的时候出现错误")
        }
        
        // 重新获取数据
        buildTagGroupList()
        
        // 清空新标签输入框
        self.newTagTitle.removeAll()
        
        // 关闭新标签添加输入框
        showNewTagInputField = false
    }
}

struct AddVision_Previews: PreviewProvider {
    static var previews: some View {
        AddVision()
            .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

字符串
我试过几种方法,但都失败了。
我应该如何修改我的代码?
谢啦,谢啦
我用谷歌搜索这个问题,关键词是这样的:
SwiftUI contextMenu不应用于子视图,而是应用于父视图
不幸的是,我没有找到我需要的东西。
我也尝试了Youbube与关键词,但我得到的T_T较少
我问GPT几次,它确实给了我一些解决方案,我尝试了所有的
全部失败T_T

pvcm50d1

pvcm50d11#

下面的代码对我来说工作正常(Xcode 15 beta 5)。如果问题仍然存在,您应该编辑您的问题并添加编译所需的所有代码(How to create a Minimal, Reproducible Example)。

struct ContentView: View {
    private let tags2DList = [["123", "456", "789"], ["987", "654", "321"]]
    
    var body: some View {
        VStack(alignment: .leading) {
            ForEach(tags2DList, id: \.self) { tagList in
                HStack {
                    ForEach(tagList, id: \.self) { tag in
                        Text(tag)
                            .font(.callout)
                            .foregroundColor(Color(hue: 0.364, saturation: 0.939, brightness: 0.628))
                            .padding()
                            .frame(height: 24.0)
                            .background(Color(hue: 0.387, saturation: 0.969, brightness: 0.965, opacity: 0.207))
                            .frame(alignment: .center)
                            .contextMenu {
                                Button {
                                    // some action
                                } label: {
                                    Label("Delete", systemImage: "trash")
                                }
                            }
                            .cornerRadius(100) // <- Changed order for better animation
                    }
                }
            }
        }
    }
}

字符串


的数据

相关问题