You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI接入UIKit自定义按钮时CGAffineTransform缩放效果异常问题

问题根因

该异常由两个交互逻辑冲突导致:

  • UIKit侧的缩放动画未配置beginFromCurrentState选项,首次触发时会从视图初始布局的临时transform状态插值,而非默认的identity,出现反向放大的视觉效果
  • SwiftUI会对托管的UIKit视图默认启用隐式动画,首次触发UIKit动画时和SwiftUI布局周期冲突,导致动画起始值异常

修复方案

第一步:修改UIKit侧CustomButton的动画实现

移除不必要的主队列异步调度,添加动画选项避免起始值异常:

private func rescaleButtonSize(scaleXto x: CGFloat = 1.0,scaleYto y: CGFloat = 1.0) {
    // 触发按钮事件的回调本身就在主线程,不需要额外调度到主队列
    UIView.animate(withDuration: 0.2, delay: 0, options: [.allowUserInteraction, .beginFromCurrentState]) {
        self.transform = CGAffineTransform(scaleX: x, y: y)
    }
}

第二步:优化UIViewRepresentable封装逻辑

移除makeUIView中不必要的主动调用updateUIView的代码,禁用更新时的隐式动画干扰:

import SwiftUI

struct SwiftUI_CustomButton: UIViewRepresentable {
    var title: String
    var handler: (() -> Void)? = nil
    
    func makeUIView(context: Context) -> CustomButton {
        let button = CustomButton()
        button.addAction {
            handler?()
        }
        // 提高内容拥抱优先级,避免SwiftUI随意拉伸按钮
        button.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        button.setContentHuggingPriority(.defaultHigh, for: .vertical)
        return button
    }

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

第三步:调整SwiftUI侧调用代码

添加fixedSize修饰符,让SwiftUI按照UIKit按钮的固有大小布局,避免强制拉伸导致transform异常:

struct CustomButton_SwiftUI: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            SwiftUI_CustomButton(
                title: "Actual"
            ) {
                // 按钮点击逻辑
            }
            .fixedSize()
        }
        .padding(16)
    }
}

内容的提问来源于stack exchange,提问作者Dreiohc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 16:00:00