nic*_*ng2 5 animation swift swiftui
我在堆栈中有一些带有动画偏移的按钮。由于某种原因,动画偏移按钮无法单击。当偏移量约为 250 左右时,按钮似乎可以单击一秒钟,然后在偏移量低于该值时再次变得不可单击...非常感谢任何帮助!
struct ContentView: View {
@State var offset: CGFloat = -300
var body: some View {
HStack {
Button(action: {
print("clickable")
}, label: {
Text("Click me")
})
Button(action: {
print("clickable2")
}, label: {
Text("Click me2")
})
Button(action: {
print("clickable3")
}, label: {
Text("Click me3")
})
}.offset(x: offset)
.onAppear(perform: {
withAnimation(.linear(duration: 10).repeatForever()) {
offset = 300
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
首先,这是预期的行为。因为当您使用时offset
,SwiftUI
显示的内容会发生变化。简而言之,这意味着SwiftUI
改变View
自身
由于onTapGesture
仅识别视图上的触摸,这也解释了为什么您可以单击偏移视图
在你的代码中,你是offsetting
你的View
第一个,然后你正在应用你的动画。当您使用 时withAnimation
,SwiftUI 会使用提供的动画重新计算视图的主体,但请记住,它不会更改之前应用于的任何内容View
。
请注意Click Me
进入红色矩形时如何变得可点击。发生这种情况是因为红色矩形表示Click Me
按钮的最终偏移量。(所以它只是一个占位符)
因此View
,它本身和offset
必须匹配,因为当您首先偏移视图时,SwiftUI
需要您的视图在那里触发点击手势。
现在我们了解了问题,我们就可以解决它了。所以,问题的发生是因为我们首先偏移视图,然后应用动画。
因此,如果这没有帮助,一种可能的解决方案可能是通过动画更改周期内的偏移量(例如,我每个周期使用 0.1 秒),因为这会导致 SwiftUI 在每次更改偏移量时重新定位视图,因此我们奇怪的错误不应该发生。
代码:
struct ContentView: View {
@State private var increment : CGFloat = 1
@State private var offset : CGFloat = 0
var body: some View {
ZStack {
Button("Click Me") {
print("Click")
}
.fontWeight(.black)
}
.tappableOffsetAnimation(offset: $offset, animation: .linear, duration: 5, finalOffsetAmount: 300)
}
}
struct TappableAnimationModifier : ViewModifier {
@Binding var offset : CGFloat
var duration : Double
var finalOffsetAmount : Double
var animation : Animation
var timerPublishInSeconds : TimeInterval = 0.1
let timer : Publishers.Autoconnect<Timer.TimerPublisher>
var autoreverses : Bool = false
@State private var decreasing = false
public init(offset: Binding<CGFloat>, duration: Double, finalOffsetAmount: Double, animation: Animation, autoreverses: Bool) {
self._offset = offset
self.duration = duration
self.finalOffsetAmount = finalOffsetAmount
self.animation = animation
self.autoreverses = autoreverses
self.timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
}
public init(offset: Binding<CGFloat>, duration: Double, finalOffsetAmount: Double, animation: Animation, timerPublishInSeconds: TimeInterval) {
self._offset = offset
self.duration = duration
self.finalOffsetAmount = finalOffsetAmount
self.animation = animation
self.timerPublishInSeconds = timerPublishInSeconds
self.timer = Timer.publish(every: timerPublishInSeconds, on: .main, in: .common).autoconnect()
}
public init(offset: Binding<CGFloat>, duration: Double, finalOffsetAmount: Double, animation: Animation) {
self._offset = offset
self.duration = duration
self.finalOffsetAmount = finalOffsetAmount
self.animation = animation
self.timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
}
func body(content: Content) -> some View {
content
.animation(animation, value: offset)
.offset(x: offset)
.onReceive(timer) { input in
/*
* a simple math here, we're dividing duration by 0.1 because our timer gets triggered
* in every 0.1 seconds, so dividing this result will always produce the
* proper value to finish offset animation in `x` seconds
* example: 300 / (5 / 0.1) = 300 / 50 = 6 increment per 0.1 second
*/
if (offset >= finalOffsetAmount) {
// you could implement autoReverses by not canceling the timer here
// and substracting finalOffsetAmount / (duration / 0.1) until it reaches zero
// then you can again start incrementing it.
if autoreverses {
self.decreasing = true
}
else {
timer.upstream.connect().cancel()
return
}
}
if offset <= 0 {
self.decreasing = false
}
if decreasing {
offset -= finalOffsetAmount / (duration / timerPublishInSeconds)
}
else {
offset += finalOffsetAmount / (duration / timerPublishInSeconds)
}
}
}
}
extension View {
func tappableOffsetAnimation(offset: Binding<CGFloat>, animation: Animation, duration: Double, finalOffsetAmount: Double) -> some View {
modifier(TappableAnimationModifier(offset: offset, duration: duration, finalOffsetAmount: finalOffsetAmount, animation: animation))
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我添加了可自定义的时间戳以及自动反转。
它看起来是这样的:
你的视图正在运行,去捕捉它 x)
归档时间: |
|
查看次数: |
601 次 |
最近记录: |