ScrollView 内的上下文菜单影响整个部分而不是按钮

问题描述 投票:0回答:1

我正在尝试将上下文菜单添加到 SwiftUI 中列表 -> 部分 -> ScrollView(水平)内的按钮。但是,当我按住按钮时,上下文菜单将应用于整个部分,而不仅仅是按钮。这是相关代码:

屏幕截图1

为什么上下文菜单应用于整个部分而不是仅应用于按钮?如何使上下文菜单仅出现在按钮上?


struct HistoryView: View {
    @StateObject private var viewModel = HistoryViewModel()

    @State private var selectedFilter: String = "all"
    @State private var oldSelectedFilter: String = "all"
    @State private var selectedItem: HistoryItem?
    @State private var selectedHistoryEdit: HistoryItem?
    @State private var showingDetailSheet: Bool = false
    @State private var showingFilterSheet: Bool = false
    
    @Environment(\.colorScheme) var colorScheme

    @State private var shouldRefreshParentView: Bool = false
    
    @State private var showingTemplateAddSheet = false
    @State private var selectedTemplateItem: TemplateItem?
    
    @AppStorage("templatesLimit") var templatesLimit: Int = 0

    var body: some View {
        VStack {
            List {
                Section {
                    filterSection
                    summarySection
                }
                
                if viewModel.isLoadingTemplates, viewModel.isLoading {
                    Section(header: Text("")
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
                    ) {
                        ScrollView(.horizontal, showsIndicators: false) {
                            HStack(spacing: 15) {
                                // Show a few skeletons while loading
                                ForEach(0..<5, id: \.self) { _ in
                                    SkeletonTemplateView()
                                }
                            }
                            .padding(.leading, 0)  // Убираем левый отступ у HStack
                            .padding(.trailing)    // Можно настроить правый отступ при необходимости
                        }
                        .listRowBackground(Color.clear)
                        .listRowInsets(EdgeInsets()) // Убираем стандартные отступы у строки
                    }
                } else {
                    templateSection
                }
    }

.listStyle(InsetGroupedListStyle())
            .navigationBarTitle("История")
            .sheet(item: $selectedItem) { item in
                HistoryDetailView(item: item, categoryDictionary: categoryDictionary, accountDictionary: accountDictionary, shouldRefreshParentView: $shouldRefreshParentView, viewModel: viewModel)
                    .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
            }
            .sheet(item: $selectedHistoryEdit) { item in
                NewView(historyItem: item, shouldRefreshParentView: $shouldRefreshParentView) // Ensure item is defined and passed properly
                    .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
            }
            .onAppear {
                Task {
                    await viewModel.loadData()
                }
            }
        }
        .refreshable {
            Task {
                await viewModel.refreshData()
            }
        }
        .onChange(of: shouldRefreshParentView) { newValue in
            if newValue {
                Task {
                    await viewModel.refreshData()
                }
                shouldRefreshParentView = false
            }
        }
    }

private var templateSection: some View {
        Section(header: Text("Шаблоны")
            .font(.callout)
            .frame(maxWidth: .infinity, alignment: .leading)
            .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
        ) {
            ScrollView(.horizontal, showsIndicators: false) {
                LazyHStack(spacing: 15) {
                    if templatesLimit > 0 {
                        Button(action: {
                            showingTemplateAddSheet = true
                        }) {
                            VStack {
                                Image(systemName: "plus")
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .frame(width: 30, height: 30)
                                    .padding()
                                    .background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white)
                                    .cornerRadius(10)
                                
                                Text("Создать")
                                    .foregroundColor(.primary)
                                    .font(.footnote)
                                    .multilineTextAlignment(.center)
                                    .padding(.top, 5)
                                    .frame(width: 80)
                            }
                            .frame(width: 80, height: 100)
                        }
                        .sheet(isPresented: $showingTemplateAddSheet) {
                            NewTemplateView(templateItem: nil, shouldRefreshParentView: $shouldRefreshParentView, defaultType: filterTypeView)
                                .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
                        }
                        .contextMenu {
                            Button("HELLO"){
                                
                            }
                        }
                    }
                    
                    ForEach(filteredTemplates) { item in
                        Button(action: {
                            selectedTemplateItem = item
                        }) {
                            VStack {
                                Image(systemName: "\(item.iconName)")
                                    .resizable()
                                    .aspectRatio(contentMode: .fit)
                                    .frame(width: 30, height: 30)
                                    .padding()
                                    .background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white)
                                    .cornerRadius(10)
                                
                                Text(item.name)
                                    .foregroundColor(.primary)
                                    .font(.footnote)
                                    .multilineTextAlignment(.center)
                                    .padding(.top, 5)
                                    .frame(width: 80)
                            }
                            .frame(width: 80, height: 100)
                        }
                    }
                    
                    // Индикатор загрузки данных в конце списка
                    if !viewModel.templateItems.isEmpty {
                        if viewModel.isLoadingTemplatesMore {
                            ForEach(0..<5, id: \.self) { _ in
                                SkeletonTemplateView()
                            }
                        } else if !viewModel.isAllTemplatesDataLoaded {
                            SkeletonTemplateView()
                                .onAppear {
                                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                                        Task {
                                            await viewModel.loadMoreTemplates()
                                        }
                                    }
                                }
                                .padding()
                        }
                    }
                }
                .padding(.leading, 0)
                .padding(.trailing)
            }
            .listRowBackground(Color.clear) // Прозрачный фон для секции
            .listRowInsets(EdgeInsets()) // Убираем стандартные отступы у строки
            .sheet(item: $selectedTemplateItem) { item in
                NewView(historyItem: nil, shouldRefreshParentView: $shouldRefreshParentView, templateItem: item) // Ensure item is defined and passed properly
                    .environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
            }
        }
    }





swiftui
1个回答
0
投票

这似乎是由于列表的布局行为造成的。除了在这种情况下不使用列表之外,我不知道任何解决方案。

这里有一些可重现的代码,您可以取消注释列表以查看差异。

import SwiftUI

struct ButtonContextMenuTest: View {
    
    var body: some View {
        // List {
            Section {
                ScrollView(.horizontal, showsIndicators: false) {
                    LazyHStack(spacing: 15) {
                        ForEach(0..<8) { index in
                            Button(action: {
                                //action here...
                            }) {
                                VStack(spacing: 10) {
                                    Image(systemName: "plus")
                                        .resizable()
                                        .aspectRatio(contentMode: .fit)
                                        .frame(width: 30, height: 30)
                                        .cornerRadius(10)
                                    
                                    Text("Button")
                                        .foregroundColor(.primary)
                                        .font(.footnote)
                                        .multilineTextAlignment(.center)
                                        .padding(.top, 5)
                                        .frame(width: 80)
                                }
                                .frame(width: 80, height: 100)
                                .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12))
                            }
                            .contextMenu {
                                Button("HELLO"){
                                }
                            }
                            
                        }
                    }
                    .padding()
                }
            }
        }
    // }
}

#Preview {
    ButtonContextMenuTest()
        .preferredColorScheme(.dark)
}

当不在列表中时,contextMenu 的行为符合预期:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.