【问题标题】:CGAffineTransform scale resize not working properly when used in SwiftUI在 SwiftUI 中使用时,CGAffineTransform 缩放调整大小无法正常工作
【发布时间】:2021-09-14 10:10:02
【问题描述】:

我尝试使用从 UIKit 创建的自定义视图按钮到使用 UIViewRepresentable 的 SwiftUI 视图,但它没有按预期工作。

预期:

点击或按住视图按钮会缩小。

实际:

最初点击时视图按钮会展开,然后松开时会缩小

自定义视图按钮在 UIKit 控制器中正常工作。

在 UIKit 中创建的自定义按钮视图

public class CustomButton: UIView {

    fileprivate var clickedBtn: (() -> Void)?
.
.
.
.

    public func addAction(withEvent event: UIControl.Event = .touchUpInside, handler clickedHandler: @escaping () -> Void) {
        button.addTarget(self, action: #selector(holdRelease(_:)), for: .touchUpInside)
        button.addTarget(self, action: #selector(holdDown(_:)), for: .touchDown)
        button.addTarget(self, action: #selector(holdRelease(_:)), for: .touchDragExit)
        }
        clickedBtn = clickedHandler
    }
    
    @objc public func holdDown(_ sender: CXButton) {
        setupUIforHoldDown()
    }
    
    @objc public func holdRelease(_ sender: CXButton) {
        setupUIForHoldRelease()
        clickedBtn?()
    }
.
.
.
.
    
    /// Button rescales when touchDown. Button resizes back to 100% once release.
    private func setupUIforHoldDown() {
        rescaleButtonSize(scaleXto: 0.95, scaleYto: 0.95)
    }
    
    private func setupUIForHoldRelease() {
        rescaleButtonSize()
    }

    private func rescaleButtonSize(scaleXto x: CGFloat = 1.0,scaleYto y: CGFloat = 1.0) {
        DispatchQueue.main.async {
            UIView.animate(withDuration: 0.2, animations: {
                self.transform = CGAffineTransform(scaleX: x, y: y)
            })
        }
    }
}

UIViewRepresentable

import SwiftUI

struct SwiftUI_CustomButton: UIViewRepresentable {
    var title: String
    var handler: (() -> Void)? = nil
    
    func makeUIView(context: Context) -> CustomButton {
        let button = CustomButton()
        updateUIView(button, context: context)
        button.addAction {
            self.handler?()
        }
        return button
    }

    func updateUIView(_ button: CustomButton, context: Context) {
        button.title = title
    }
}

Swift UI 视图

struct CustomButton_SwiftUI: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            
            SwiftUI_CustomButton(
                title: "Actual"
            ) {
                // Button Action
            }
        }
        .padding(16)
    }
}

编辑:我仍在使用 UIKit 自定义视图,因为它也用于某些 UIKit 控制器。

【问题讨论】:

    标签: ios swiftui cgaffinetransform custom-view uiviewrepresentable


    【解决方案1】:

    您可以在没有 UIKit 的情况下使用自定义 ButtonStyle

    struct CustomButtonStyle: ButtonStyle {
        func makeBody(configuration: Configuration) -> some View {
            configuration.label
                .foregroundColor(Color.accentColor)
                .scaleEffect(configuration.isPressed ? 0.95 : 1)
                .animation(.easeIn(duration: 0.2), value: configuration.isPressed)
        }
    }
    

    用法:

    Button(action: {}) {
        Text("Actual")
            .frame(height: 45)
            .frame(maxWidth: .infinity)
            .background(Color.black)
            .padding()
    }.buttonStyle(CustomButtonStyle())
    

    结果:

    【讨论】:

    • 是的,这可能是我最后的选择,但自定义视图也用于 UIKit 控制器,这就是我希望它工作的原因。谢谢菲利普
    • @Dreiohc 在 UIKit 你的代码工作正常,似乎 SwiftUI 和 UIKit 动画之间存在一些冲突。似乎当您使用变换更改视图大小时,SwiftUI 会将其大小更改为原始值。我能够通过添加容器视图并更改此视图的转换来运行动画。但是这个容器的大小也不应该在动画期间在layoutSubviews 中更新。我建议你不要把 UIKit 动画和 SwiftUI 动画混在一起,在不同的平台上使用不同的按钮。
    • 你说这可能是使用转换时 UIKit 和 SwiftUI 不兼容的问题?
    • @Dreiohc 完全正确。
    猜你喜欢
    • 2014-04-03
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多