October 23, 2024
Chicago 12, Melborne City, USA
PHP

Context Menu Inside ScrollView Affects Entire Section Instead of Button in SwiftUI


Question 1: I am trying to add a context menu to a button inside a List -> Section -> ScrollView (horizontal) in SwiftUI. However, when I press and hold on the button, the context menu gets applied to the entire Section instead of just the button. Here’s the relevant code:

SCREENSHOT 1

Why is the context menu being applied to the whole Section instead of just the button? How can I make the context menu appear only for the button?

Question 2: I have a templateSection view where I load some template items and display them in a horizontal scroll. However, whenever I change the filter type or load more templates, the skeleton loading view starts acting weirdly — it flickers or doesn’t display correctly.

VIDEO (GIF) 2

Here’s the part of my code where I define the section with a ScrollView and LazyHStack:

When I scroll or change the filter, the skeleton loading view glitches or behaves strangely. What could be causing this issue, and how can I fix it?


Section(header: Text("Templates")) {
    ScrollView(.horizontal, showsIndicators: false) {
        LazyHStack(spacing: 15) {
            Button(action: {
                // Action to add a new template
            }) {
                VStack {
                    Image(systemName: "plus")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 30, height: 30)
                        .padding()
                        .background(Color.white)
                        .cornerRadius(10)

                    Text("Create")
                        .foregroundColor(.primary)
                        .font(.footnote)
                        .multilineTextAlignment(.center)
                        .padding(.top, 5)
                        .frame(width: 80)
                }
                .frame(width: 80, height: 100)
            }
            .contextMenu {
                Button("Hello") {
                    // Context menu action
                }
            }
        }
    }
}


private var templateSection: some View {
    Section(header: Text("Templates")) {
        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(Color.white)
                                .cornerRadius(10)

                            Text("Create")
                                .foregroundColor(.primary)
                                .font(.footnote)
                                .multilineTextAlignment(.center)
                                .padding(.top, 5)
                                .frame(width: 80)
                        }
                        .frame(width: 80, height: 100)
                    }
                    .sheet(isPresented: $showingTemplateAddSheet) {
                        NewTemplateView(shouldRefreshParentView: $shouldRefreshParentView)
                    }
                }

                ForEach(filteredTemplates) { item in
                    Button(action: {
                        selectedTemplateItem = item
                    }) {
                        VStack {
                            Image(systemName: "\(item.iconName)")
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .frame(width: 30, height: 30)
                                .padding()
                                .background(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.isLoadingTemplatesMore {
                    ForEach(0..<5, id: \.self) { _ in
                        SkeletonLoadingView()
                            .frame(width: 80, height: 100)
                    }
                }
            }
        }
    }
}



var filteredItems: [HistoryItem] {
        switch selectedFilter {
        case "expense":
            return viewModel.historyItems.filter { $0.type == "expense" }
        case "income":
            return viewModel.historyItems.filter { $0.type == "income" }
        default:
            return viewModel.historyItems
        }
    }
    
    var filteredTemplates: [TemplateItem] {
        switch selectedFilter {
        case "expense":
            return viewModel.templateItems.filter { $0.type == "expense" }
        case "income":
            return viewModel.templateItems.filter { $0.type == "income" }
        default:
            return viewModel.templateItems.filter { $0.type == "income" }
        }
    }



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
                }
                
                
                if viewModel.isLoading {
                    Section {
                        // Показываем скелетоны вместо реальных данных, пока данные загружаются
                        SkeletonHistorySectionView()
                    }
                } else if selectedFilter != oldSelectedFilter, filteredItems.isEmpty {
                    // Индикатор подгрузки данных в конце списка
                    if !viewModel.historyItems.isEmpty {
                        if viewModel.isLoadingMore {
                            SkeletonHistorySectionView()
                                .padding(.top)
                                .padding(.bottom)
                        } else if !viewModel.isAllDataLoaded {
                            SkeletonHistorySectionView()
                                .onAppear {
                                    Task {
                                        await viewModel.loadMoreHistory()
                                    }
                                }
                                .padding(.top)
                                .padding(.bottom)
                        }
                    }
                } else if filteredItems.isEmpty {
                    Section {
                        VStack {
                            Spacer()
                            Text("Нет доступных записей")
                                .foregroundColor(.gray)
                                .padding()
                            Spacer()
                        }
                        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
                    }
                } else {
                    ForEach(groupedItems, id: \.key) { date, items in...



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video