gpt4 book ai didi

ios - 如何在 SwiftUI 中通过点击手势制作放大缩小按钮动画?

转载 作者:行者123 更新时间:2023-12-01 17:00:28 24 4
gpt4 key购买 nike

为按钮设置凹凸效果的简单且常规的方法,但在 SwiftUI 中并不简单。

我正在尝试更改 tapGesture 修饰符中的 scale,但没有任何效果。我不知道如何制作动画链,可能是因为 SwiftUI 没有它。所以我天真的做法是:

@State private var scaleValue = CGFloat(1)

...

Button(action: {
withAnimation {
self.scaleValue = 1.5
}

withAnimation {
self.scaleValue = 1.0
}
}) {
Image("button1")
.scaleEffect(self.scaleValue)
}

显然它不起作用,按钮图像立即获取最后的比例值。

我的第二个想法是在 hold 事件上将比例更改为 0.8 值,然后在 release 事件之后将比例更改为 1.2 几毫秒后再次将其更改为 1.0。我想这个算法应该会产生漂亮且更自然的凹凸效果。但我在 SwiftUI 中找不到合适的 gesture 结构来处理 hold-n-release 事件。

附注为了便于理解,我将描述 hold-n-release 算法的步骤:

  1. 比例值为1.0
  2. 用户触摸按钮
  3. 按钮比例变为0.8
  4. 用户释放按钮
  5. 按钮比例变为1.2
  6. 延迟0.1
  7. 按钮比例恢复为默认1.0

UPD:我找到了一个使用动画delay修饰符的简单解决方案。但我不确定它是否正确且清晰。它还不涵盖 hold-n-release 问题:

@State private var scaleValue = CGFloat(1)

...

Button(action: {
withAnimation {
self.scaleValue = 1.5
}

//
// Using delay for second animation block
//
withAnimation(Animation.linear.delay(0.2)) {
self.scaleValue = 1.0
}
}) {
Image("button1")
.scaleEffect(self.scaleValue)
}

UPD 2:我注意到在上面的解决方案中,我将什么值作为参数传递给 delay 修饰符并不重要:0.21000 将具有相同的效果。也许这是一个错误🐞

所以我使用了 Timer 实例而不是 delay 动画修饰符。现在它正在按预期工作:

...

Button(action: {
withAnimation {
self.scaleValue = 1.5
}

//
// Replace it
//
// withAnimation(Animation.linear.delay(0.2)) {
// self.scaleValue = 1.0
// }
//
// by Timer with 0.5 msec delay
//
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
withAnimation {
self.scaleValue = 1.0
}
}
}) {
...

UPD 3:在等待Apple官方更新之前,实现touchStarttouchEnd两个事件的合适解决方案之一是基于@average Joe answer :

import SwiftUI

struct TouchGestureViewModifier: ViewModifier {

let minimumDistance: CGFloat
let touchBegan: () -> Void
let touchEnd: (Bool) -> Void

@State private var hasBegun = false
@State private var hasEnded = false

init(minimumDistance: CGFloat, touchBegan: @escaping () -> Void, touchEnd: @escaping (Bool) -> Void) {
self.minimumDistance = minimumDistance
self.touchBegan = touchBegan
self.touchEnd = touchEnd
}

private func isTooFar(_ translation: CGSize) -> Bool {
let distance = sqrt(pow(translation.width, 2) + pow(translation.height, 2))
return distance >= minimumDistance
}

func body(content: Content) -> some View {
content.gesture(DragGesture(minimumDistance: 0)
.onChanged { event in
guard !self.hasEnded else { return }

if self.hasBegun == false {
self.hasBegun = true
self.touchBegan()
} else if self.isTooFar(event.translation) {
self.hasEnded = true
self.touchEnd(false)
}
}
.onEnded { event in
if !self.hasEnded {
let success = !self.isTooFar(event.translation)
self.touchEnd(success)
}
self.hasBegun = false
self.hasEnded = false
}
)
}
}

extension View {
func onTouchGesture(minimumDistance: CGFloat = 20.0,
touchBegan: @escaping () -> Void,
touchEnd: @escaping (Bool) -> Void) -> some View {
modifier(TouchGestureViewModifier(minimumDistance: minimumDistance, touchBegan: touchBegan, touchEnd: touchEnd))
}
}

最佳答案

struct ScaleButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.scaleEffect(configuration.isPressed ? 2 : 1)
}
}

struct Test2View: View {
var body: some View {
Button(action: {}) {
Image("button1")
}.buttonStyle(ScaleButtonStyle())
}
}

关于ios - 如何在 SwiftUI 中通过点击手势制作放大缩小按钮动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58037105/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com