Вот код тестирования:
import SwiftUI
struct ContentView: View {
@State private var pad: Bool = false
@State private var showDot: Bool = true
var body: some View {
VStack {
Button {showDot.toggle()} label: {Text("Toggle Show Dot")}
Spacer().frame(height: pad ? 100 : 10)
Circ(showDot: showDot)
Spacer()
}.onAppear {
withAnimation(.linear(duration: 3).repeatForever()) {pad = true}
}
}
}
struct Circ: View {
let showDot: Bool
var body: some View {
Circle().stroke().frame(height: 50).overlay {if showDot {Circle().frame(height: 20)}}
}
}
Бывает, что после того, как я переключаю showDot
, круг точек снова не находится в центре круга штриха! Как я могу это исправить?
Представление Circ
дано, я не могу изменить это представление!
Редактировать
Если вы можете просто скрыть представление, см. решение 1, которое предпочтительнее. Если вам нужно перестроить представление, см. решение 2.
Решение 1
Замените условие if
модификатором .opacity()
, который читается как 1, когда showDot
равно true
.
Таким образом, точка не исчезает полностью, она есть, но ее просто не видно. Вы будете переключать видимость, а не сам вид.
Как это:
@State private var pad: Bool = false
@State private var showDot: Bool = true
var body: some View {
VStack {
Button {
showDot.toggle()
} label: {
Text("Toggle Show Dot")
}
Spacer()
.frame(height: pad ? 100 : 10)
Circle().stroke()
.frame(height: 50)
.overlay {
Circle()
.frame(height: 20)
.opacity(showDot ? 1 : 0) // <- Here
}
Spacer()
}
.onAppear {
withAnimation(.linear(duration: 3).repeatForever()) {pad = true}
}
}
Решение 2
Анимацию можно заменить таймером. Каждый раз, когда он срабатывает, он будет перемещать весь вид, изменяя высоту Spacer()
.
// These variables will track the position and moving direction of the dot
@State private var pos: CGFloat = 0
@State private var movingUp = false
@State private var showDot: Bool = true
// This variable will change the position
// This is a dummy iniatialization, the .onAppear modifier sets the real timer
@State private var timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in }
var body: some View {
VStack {
Button {
showDot.toggle()
} label: {
Text("Toggle Show Dot")
}
Spacer()
.frame(height: pos)
Circle().stroke()
.frame(height: 50)
.overlay {
if showDot {
Circle().frame(height: 20)
}
}
Spacer()
}
.onAppear {
// The timer interval will define the speed
timer = Timer.scheduledTimer(withTimeInterval: 0.02, repeats: true) { _ in
moveCircle()
}
}
}
private func moveCircle() {
if movingUp {
if pos <= 0 {
pos = 0
movingUp = false
} else {
pos -= 1
}
} else {
if pos >= 100 {
pos = 100
movingUp = true
} else {
pos += 1
}
}
}
@ 蘇哲聖, анимация применяется к существующим представлениям, если вы удалите представление, а затем вставите новое (поскольку оно новое), текущая анимация к нему не применяется, вам нужно остановить запущенную анимацию и перезапустить ее снова, чтобы применить к новому виду. . Так что это единственное решение для сценария, описанного в исходном вопросе... Или вам нужно обновить свой вопрос, добавив более точное описание того, что действительно необходимо в вашем приложении.
@ 蘇哲聖: см. отредактированное решение, если оно вам подходит.
Метод таймера работает. Благодарю вас!
В моей реальной ситуации, когда
showDot == false
, я не могу получить «Точечный вид». Следовательно, метод непрозрачности не может применяться.