Я работаю над простым видом, в котором onAppear
рисуется путь от 3-го круга до первого, а затем ко второму. Я использую GeometryReader
и PreferenceKey
, чтобы получить реальные позиции. Похоже, я правильно определил центр круга, но кажется, что он сместился немного ниже, чем должно быть.
Может ли кто-нибудь указать, что не так?
Вот мой код:
struct ScreenPath: View {
@State private var end = CGFloat.zero
var positions: [CGPoint]
var body: some View {
Path { lineBuilder in
let pathSequence = [positions[2], positions[0], positions[1]]
if let start = pathSequence.first {
lineBuilder.move(to: start)
lineBuilder.addLine(to: pathSequence[1])
lineBuilder.addLine(to: pathSequence[2])
}
}
.trim(from: 0, to: end)
.stroke(Color.green, lineWidth: 4)
.animation(.easeIn(duration: 1.5))
.onAppear {
self.end = 1
}
}
}
struct HomeScreen: View {
@State private var circlePositions: [CGPoint] = []
@State private var colors: [Color] = [.white, .white, .white, .white]
@State private var showPath: Bool = false
var body: some View {
GeometryReader { geo in
ZStack {
if showPath {
ScreenPath(positions: circlePositions)
}
VStack(spacing: 30) {
VStack(spacing: 45) {
HStack {
Circle()
.fill(colors[0])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .global).center])
})
Spacer().frame(width: 50)
Circle()
.fill(colors[1])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .global).center])
})
}
HStack {
Circle()
.fill(colors[2])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .global).center])
})
Spacer().frame(width: 50)
Circle()
.fill(colors[3])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .global).center])
})
}
}
}
.frame(width: geo.size.width, height: geo.size.height, alignment: .center)
}
.onPreferenceChange(CirclePositionKey.self) { positions in
if positions.count == 4 {
circlePositions = positions
for position in positions {
print("Circle position: \(position)")
}
}
}
.onAppear {
colors[0] = .green
colors[1] = .green
colors[2] = .green
showPath.toggle()
}
}
.border(Color.red)
}
}
extension CGRect {
var center: CGPoint {
return CGPoint(x: self.midX, y: self.midY)
}
}
struct CirclePositionKey: PreferenceKey {
typealias Value = [CGPoint]
static var defaultValue: [CGPoint] = []
static func reduce(value: inout [CGPoint], nextValue: () -> [CGPoint]) {
value.append(contentsOf: nextValue())
}
}
Вы снимаете кадр в координатном пространстве .global
. Начало этого координатного пространства находится в самом верхнем левом углу экрана, игнорируя безопасную область.
При рисовании Path
координатное пространство — это локальное координатное пространство представления Path
, которое учитывает безопасную область. Начало этого координатного пространства находится внутри безопасной зоны.
Итак, простой способ исправить это — сделать ignoresSafeArea
на пути:
Path {
...
}
.trim(from: 0, to: end)
.stroke(Color.green, lineWidth: 4)
.ignoresSafeArea()
.animation(.easeIn(duration: 1.5), value: end)
.onAppear {
self.end = 1
}
Тем не менее, я бы рекомендовал вместо этого объявить собственное координатное пространство, как в этом вопросе, чтобы у вас было больше контроля.
Вот пример использования координатного пространства VStack
и использования backgroundPreferenceValue , чтобы поместить путь под кругами (таким образом вам не понадобится ZStack
):
struct ContentView: View {
@State private var colors: [Color] = [.white, .white, .white, .white]
@State private var showPath: Bool = false
var body: some View {
GeometryReader { geo in
VStack(spacing: 30) {
VStack(spacing: 45) {
HStack {
Circle()
.fill(colors[0])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .named("DrawingArea")).center])
})
Spacer().frame(width: 50)
Circle()
.fill(colors[1])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .named("DrawingArea")).center])
})
}
HStack {
Circle()
.fill(colors[2])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .named("DrawingArea")).center])
})
Spacer().frame(width: 50)
Circle()
.fill(colors[3])
.frame(width: 30, height: 30)
.background(GeometryReader { circleGeo in
Color.clear.preference(key: CirclePositionKey.self, value: [circleGeo.frame(in: .named("DrawingArea")).center])
})
}
}
}
.frame(width: geo.size.width, height: geo.size.height, alignment: .center)
.coordinateSpace(.named("DrawingArea"))
.backgroundPreferenceValue(CirclePositionKey.self) { positions in
if showPath {
ScreenPath(positions: positions)
}
}
.onAppear {
colors[0] = .green
colors[1] = .green
colors[2] = .green
showPath.toggle()
}
}
.border(Color.red)
}
}
@JeevanDanielMahtani Я знал, что это ты :) Я положил это сюда для будущих читателей. И, как и в этом вопросе, я бы использовал координатное пространство ZStack
. Тем не менее, я также подумал о другой идее. Используйте backgroundPreferenceValue , чтобы нарисовать путь в качестве фона VStack
, и вам вообще не понадобится ZStack
. Конечно, в этом случае вы бы использовали систему координат VStack
.
@JeevanDanielMahtani Я отредактировал, чтобы продемонстрировать, как это сделать с помощью backgroundPreferenceValue
.
О, я не осознавал, что путь находится в безопасной зоне. Спасибо, что обратили на это мое внимание. ха-ха, на самом деле я был тем человеком, который задал вопрос в той теме, на которую вы ссылаетесь :). Однако для меня это было информативно, и я обязательно переключусь на использование собственного координатного пространства, спасибо за предложение. Я думаю, было бы лучше использовать координатное пространство VStack, в котором находятся оба моих HStacks?