Я создаю представление SwiftUI с двумя синхронизированными областями прокрутки:
Горизонтальный элемент ScrollView, отображающий список разделов.
Вертикальный элемент ScrollView, отображающий содержимое, соответствующее этим разделам.
Проблема:
Реализация работает, когда каждый раздел имеет одинаковое количество элементов. Однако если разделы содержат разное количество элементов, синхронизация прерывается, и вертикальный элемент ScrollView часто прокручивается к неправильному разделу. Вот пример моего кода:
struct ContentView: View {
// Sample data
private let sections = (1...10).map { sectionIndex in
SectionData(
name: "Section \(sectionIndex)",
items: (1...(Int.random(in: 80...150))).map { "Item \($0)" }
)
}
@State private var selectedSection: String? = nil
@State private var currentVisibleSection: String? = nil
var body: some View {
VStack(spacing: 0) {
// Horizontal Selector
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(sections) { section in
Button(action: {
selectedSection = section.name
}) {
Text(section.name)
.font(.headline)
.padding(.horizontal, 10)
.padding(.vertical, 5)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(currentVisibleSection == section.name ? Color.blue : Color.gray.opacity(0.2))
)
.foregroundColor(currentVisibleSection == section.name ? .white : .primary)
}
}
}
.padding()
}
.background(Color(UIColor.systemGroupedBackground))
// Vertical Scrollable Content
ScrollViewReader { proxy in
ScrollView(.vertical, showsIndicators: false) {
LazyVStack(spacing: 20) {
ForEach(sections) { section in
VStack(alignment: .leading, spacing: 10) {
// Section Header
SectionHeader(name: section.name)
.id(section.name) // Each section has a unique ID
// Section Content
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3), spacing: 10) {
ForEach(section.items, id: \.self) { item in
Text(item)
.frame(height: 100)
.frame(maxWidth: .infinity)
.background(Color.blue.opacity(0.2))
.cornerRadius(8)
}
}
}
.background(
GeometryReader { geo in
Color.clear.preference(
key: VisibleSectionPreferenceKey.self,
value: [section.name: calculateVisibleHeight(geo)]
)
}
)
}
}
.onPreferenceChange(VisibleSectionPreferenceKey.self) { visibleSections in
updateLargestVisibleSection(visibleSections)
}
.onChange(of: selectedSection) { sectionName in
guard let sectionName else { return }
withAnimation {
proxy.scrollTo(sectionName, anchor: .top)
}
}
}
}
}
}
// Update the largest visible section
private func updateLargestVisibleSection(_ visibleSections: [String: CGFloat]) {
if let largestVisibleSection = visibleSections.max(by: { $0.value < $1.value })?.key {
currentVisibleSection = largestVisibleSection
}
}
// Calculate the visible height of a section
private func calculateVisibleHeight(_ geometry: GeometryProxy) -> CGFloat {
let frame = geometry.frame(in: .global)
let screenHeight = UIScreen.main.bounds.height
return max(0, min(frame.maxY, screenHeight) - max(frame.minY, 0))
}
}
// PreferenceKey to track visible sections
private struct VisibleSectionPreferenceKey: PreferenceKey {
static var defaultValue: [String: CGFloat] = [:]
static func reduce(value: inout [String: CGFloat], nextValue: () -> [String: CGFloat]) {
value.merge(nextValue(), uniquingKeysWith: max)
}
}
// Supporting Views and Models
struct SectionHeader: View {
let name: String
var body: some View {
Text(name)
.font(.headline)
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.gray.opacity(0.2))
}
}
struct SectionData: Identifiable {
var id: String { name }
let name: String
let items: [String]
}
LazyVStack: хорошо работает для повышения производительности, но синхронизация прерывается, когда разделы содержат разное количество элементов.
VStack: исправления проблемы с синхронизацией, но приводит к снижению производительности при работе с большими наборами данных, поскольку весь контент быстро загружается в память.
Кроме того, взаимодействие с ленивым подпредставления (например, LazyVGrid) внутри VStack вызывает скачки прокрутки, что нарушает работу пользователя.
onPreferenceChange: используется специальный PreferenceKey для отслеживания видимых разделов. , но этот подход становится ненадежным из-за ленивой загрузки разделов и динамического подсчета элементов.
Я создаю представление SwiftUI с двумя синхронизированными областями прокрутки: [list] [*]Горизонтальный элемент ScrollView, отображающий список разделов. [*]Вертикальный элемент ScrollView, отображающий содержимое, соответствующее этим разделам. [/list] [b]Проблема:[/b] Реализация работает, когда каждый раздел имеет одинаковое количество элементов. Однако если разделы содержат разное количество элементов, синхронизация прерывается, и вертикальный элемент ScrollView часто прокручивается к неправильному разделу. Вот пример моего кода: [code]struct ContentView: View { // Sample data private let sections = (1...10).map { sectionIndex in SectionData( name: "Section \(sectionIndex)", items: (1...(Int.random(in: 80...150))).map { "Item \($0)" } ) }
@State private var selectedSection: String? = nil @State private var currentVisibleSection: String? = nil
// Supporting Views and Models struct SectionHeader: View { let name: String
var body: some View { Text(name) .font(.headline) .padding() .frame(maxWidth: .infinity, alignment: .leading) .background(Color.gray.opacity(0.2)) } }
struct SectionData: Identifiable { var id: String { name } let name: String let items: [String] }
[/code] [list] [*]LazyVStack: хорошо работает для повышения производительности, но синхронизация прерывается, когда разделы содержат разное количество элементов. [*]VStack: исправления проблемы с синхронизацией, но приводит к снижению производительности при работе с большими наборами данных, поскольку весь контент быстро загружается в память. [/list] [list] [*]Кроме того, взаимодействие с ленивым подпредставления (например, LazyVGrid) внутри VStack вызывает скачки прокрутки, что нарушает работу пользователя. [/list] [list] [*]onPreferenceChange: используется специальный PreferenceKey для отслеживания видимых разделов. , но этот подход становится ненадежным из-за ленивой загрузки разделов и динамического подсчета элементов. [/list]
Я пытаюсь создать мультикурсор с вертикальной линией, которая проходит через весь подграфик, и горизонтальной линией, которая проходит только через тот подграфик, на котором в данный момент находится моя мышь.
Единственная проблема заключается в...
Я пытаюсь создать мультикурсор с вертикальной линией, которая проходит через весь подграфик, и горизонтальной линией, которая проходит только через тот подграфик, на котором в данный момент находится моя мышь.
Единственная проблема заключается в...
У меня есть график KDE, созданный с помощью seaborn, на который я накладываю несколько разрозненных точек определенного размера. Мне нужно иметь две цветные полосы для представления данных KDE и размера разбросанных значений (как показано ниже).
Я...