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:
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.
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