如何在SwiftUI的点击手势上放大或缩小按钮动画?

时间:2019-09-21 03:48:02

标签: ios swiftui

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

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

@State private var scaleValue = CGFloat(1)

...

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

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

显然它不起作用,按钮图像立即获得上一个比例值。

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

P.S。为了便于理解,我将描述hold-n-release算法的步骤:

  1. 小数位数为hold-n-release
  2. 用户触摸按钮
  3. 按钮刻度变为1.0
  4. 用户释放按钮
  5. 按钮刻度变为0.8
  6. 延迟1.2
  7. 按钮比例返回到默认的0.1

UPD::我找到了使用动画1.0修饰符的简单解决方案。但是我不确定这是正确和明确的。此外,它也不涵盖delay问题:

hold-n-release

UPD 2 : 我在上面的解决方案中注意到,作为参数传递给@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) } 修饰符的值并不重要:delay0.2将具有相同的效果。也许是个虫?

因此,我使用了1000实例而不是Timer动画修改器。现在它可以按预期工作:

delay

UPD 3 : 在我们等待苹果官方更新之前,一种用于实现两个事件... 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 } } }) { ... touchStart的合适解决方案是基于@average Joe answer的:

touchEnd

3 个答案:

答案 0 :(得分:6)

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())
    }
}

答案 1 :(得分:1)

是的,它看起来像个错误,但经过试验,我发现您可以这样做

我已经在https://youtu.be/kw4EIOCp78g上发布了一个演示

struct TestView: View {
    @State private var scaleValue = CGFloat(1)

    var body: some View {
        ZStack {
            CustomButton(
                touchBegan: {
                    withAnimation {
                        self.scaleValue = 2
                    }
                },
                touchEnd: {
                   withAnimation {
                        self.scaleValue = 1
                   }
                }
            ){
                Image("button1")
            }.frame(width: 100, height: 100)
            Image("button1").opacity(scaleValue > 1 ? 1 : 0).scaleEffect(self.scaleValue)
        }
    }
}

struct CustomButton<Content: View>: UIViewControllerRepresentable {
    var content: Content
    var touchBegan: () -> ()
    var touchEnd: () -> ()

    typealias UIViewControllerType = CustomButtonController<Content>

    init(touchBegan: @escaping () -> (), touchEnd: @escaping () -> (), @ViewBuilder content: @escaping () -> Content) {
        self.touchBegan = touchBegan
        self.touchEnd = touchEnd
        self.content = content()
    }


    func makeUIViewController(context: Context) -> UIViewControllerType {
        CustomButtonController(rootView: self.content, touchBegan: touchBegan, touchEnd: touchEnd)
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

    }
}


class CustomButtonController<Content: View>: UIHostingController<Content> {
    var touchBegan: () -> ()
    var touchEnd: () -> ()

    init(rootView: Content, touchBegan: @escaping () -> (), touchEnd: @escaping () -> ()) {
        self.touchBegan = touchBegan
        self.touchEnd = touchEnd
        super.init(rootView: rootView)
        self.view.isMultipleTouchEnabled = true
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        self.touchBegan()
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event)
        self.touchEnd()
    }

    //touchesEnded only works if the user moves his finger beyond the bound of the image and releases
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        self.touchEnd()
    }
}

还有另外一件奇怪的事情,如果我们将第二张图片缩放到第一张图片,那么如果没有.frame(width: 100, height: 100),它将不会显示。

答案 2 :(得分:1)

干净整洁的import pandas as pd df1 = pd.DataFrame({'S':[1,0.613,0.613,0.387,0], 'V1': [0,0.387,0,0.613,1],'V2': [0,0,0.387,0,0]}) print(df1) S V1 V2 0 1.000 0.000 0.000 1 0.613 0.387 0.000 2 0.613 0.000 0.387 3 0.387 0.613 0.000 4 0.000 1.000 0.000 解决方案:

swiftUI

但是,您还需要将此代码段添加到项目中:

@State private var scaleValue = CGFloat(1)

...

Image("button1")
    .scaleEffect(self.scaleValue)
    .onTouchGesture(
        touchBegan: { withAnimation { self.scaleValue = 1.5 } },
        touchEnd: { _ in withAnimation { self.scaleValue = 1.0 } }
    )