My process is to make a scrollview, which receives an array of strings and an overlay, which is positioned within the heart. When some view will get into this overlay, it ought to instantly align to its borders, that’s, be within the heart of the display screen. The checklist ought to begin from the center of the display screen with the primary ingredient.
I used to be in search of an answer right here textual content
I’ve struct
struct Area: Equatable, Hashable {
let title: String
}
PreferenceKeyStruct
struct ViewOffsetKey: PreferenceKey {
static var defaultValue: [String: CGRect] = [:]
static func cut back(worth: inout [String: CGRect], nextValue: () -> [String: CGRect]) {
worth.merge(nextValue(), uniquingKeysWith: { $1 })
}
}
and subView
struct RegionView: View {
let title: String
var physique: some View {
HStack {
Textual content(self.title)
.foregroundColor(.white)
.font(.system(.physique))
Spacer()
}
.padding(16)
.body(width: 348, alignment: .topLeading)
.background(Colour.black)
.cornerRadius(50)
.id(title)
.background(GeometryReader {
Colour.clear.choice(key: ViewOffsetKey.self,
worth: [name: $0.frame(in: .global)])
})
}
}
The principle view is realized by CurrentValueSubject and AnyPublisher.
I examine if subView intersects a rectangle with a top of 1, then I write it as displayed. When the scroll ends, I name the scrollTo technique
struct RegionListView: View {
let detector: CurrentValueSubject<[String: CGRect], By no means>
let writer: AnyPublisher<[String: CGRect], By no means>
let areas: [Region] = [
Region(name: "Region 1"),
Region(name: "Region 2"),
Region(name: "Region 3"),
Region(name: "Region 4"),
Region(name: "Region 5"),
Region(name: "Region 6"),
Region(name: "Region 7"),
Region(name: "Region 8"),
Region(name: "Region 9"),
Region(name: "Region 10"),
Region(name: "Region 11"),
Region(name: "Region 12"),
Region(name: "Region 13"),
Region(name: "Region 14"),
Region(name: "Region 15"),
Region(name: "Region 16"),
Region(name: "Region 17"),
Region(name: "Region 18"),
Region(name: "Region 19"),
Region(name: "Region 20"),
]
@State non-public var topVisibleChildId: String?
init() {
let detector = CurrentValueSubject<[String: CGRect], By no means>([:])
self.writer = detector
.debounce(for: .seconds(0.1), scheduler: DispatchQueue.primary)
.dropFirst()
.eraseToAnyPublisher()
self.detector = detector
}
var physique: some View {
GeometryReader { geometryReader in
ScrollViewReader { proxy in
ScrollView {
VStack(spacing: 8) {
ForEach(self.areas, id: .self) { area in
RegionView(title: area.title)
}
}
.body(maxWidth: .infinity)
.onPreferenceChange(ViewOffsetKey.self) { childFrames in
detector.ship(childFrames)
var visibleChildIds = [String]()
let screenMid = geometryReader.dimension.top / 2 + 56
for (id, childFrame) in childFrames the place childFrame.intersects(CGRect(x: 0, y: Int(screenMid), width: .max, top: 56)) {
print("id (id) childFrame (childFrame)")
visibleChildIds.append(id)
}
visibleChildIds.type()
if let first = visibleChildIds.first {
topVisibleChildId = first
}
}
}
.safeAreaPadding(.high, geometryReader.dimension.top / 2 - 28)
.safeAreaPadding(.backside, geometryReader.dimension.top / 2 - 28)
.background(Colour.black)
.onReceive(writer) { _ in
proxy.scrollTo(topVisibleChildId, anchor: .heart)
}
.overlay(
Textual content("High Seen Baby: (topVisibleChildId ?? "")")
.padding()
.background(Colour.blue.opacity(1))
.foregroundColor(.white)
.cornerRadius(10),
alignment: .high
)
.overlay(
Rectangle()
.body(maxWidth: .infinity)
.body(top: 56)
.foregroundColor(Colour.clear)
.border(.inexperienced, width: 4),
alignment: .heart
)
}
}
}
}
My query: is it doable to implement a conduct through which altering cells can be just like selecting a time when setting an alarm. That’s, the cell is not going to should be scrolled to the middle if the consumer didn’t end scrolling within the center. I hope I defined it clearly.