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

使用UIViewRepresentable使UIView兼容SwiftUI无渲染效果问题排查

UIKit视图封装SwiftUI后不渲染的排查与解决

问题场景

原有UIKit视图ProfileAboutMeView在UIKit环境运行正常,通过UIViewRepresentable封装后在SwiftUI中完全不渲染,相关代码如下:

原UIKit视图代码

class ProfileAboutMeView: ProfileCardGenericView {
    var profileCardVariant: ProfileCardVariant = .meet

    var commentableButton: CommentableButton?

    private lazy var titleLabel: UILabel = {
        var titleLabel = UILabel()
        titleLabel.numberOfLines = 1
        return titleLabel
    }()

    var aboutLabel: UILabel = {
        var aboutLabel = UILabel()
        aboutLabel.numberOfLines = 0
        return aboutLabel
    }()

    init(profile: Profile, profileCardVariant: ProfileCardVariant = .meet, isCommentable: Bool = false, commentButtonDelegate: CommentableButtonDelegate? = nil) {
        super.init()
        self.profileCardVariant = profileCardVariant
        self.backgroundColor = .primaryLight

        if profileCardVariant == .spotlight || profileCardVariant == .meet {
            titleLabel.attributedText = TextStyle.header3.withColor(.primaryLightTextGray).withLineBreakMode(.byTruncatingMiddle).withAlignment(.left).attributedString("Profile.About.Title".localized)
            aboutLabel.attributedText = TextStyle.header4.withColor(.black).withLineBreakMode(.byWordWrapping).withAlignment(.left).attributedString(profile.aboutMe)
            self.setCorner()
        } else {
            titleLabel.attributedText = TextStyle.header3.withLineBreakMode(.byTruncatingMiddle).withAlignment(.left).attributedString("Profile.About.Title".localized)
            aboutLabel.attributedText = TextStyle.body.withColor(.black).withLineBreakMode(.byWordWrapping).withAlignment(.left).attributedString(profile.aboutMe)
        }

        self.addSubview(titleLabel)
        self.addSubview(aboutLabel)
        if isCommentable {
            self.commentableButton = CommentableButton(for: .about, delegate: commentButtonDelegate)
            self.addSubview(commentableButton)
        }
    }

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

    override func update(forProfile profile: Profile) {
        if let attText = aboutLabel.attributedText {
            let mutableText = NSMutableAttributedString(attributedString: attText)
            mutableText.mutableString.setString(profile.aboutMe)
            aboutLabel.attributedText = mutableText
        }

        self.setNeedsLayout()
    }

    override func layoutView() {
        print("layour profile about me view")
        titleLabel.snp.makeConstraints { make in
            make.top.leading.equalToSuperview().inset(16)
        }

        if let commentableButton, commentableButton.isDescendant(of: self) {
            aboutLabel.snp.makeConstraints { make in
                make.leading.trailing.equalToSuperview().inset(16)
                make.top.equalTo(titleLabel.snp.bottom).offset(4)
                make.bottom.equalTo(commentableButton.snp.top).offset(-16)
            }

            self.commentableButton?.snp.makeConstraints { make in
                make.leading.trailing.equalToSuperview().inset(20)
                make.bottom.equalToSuperview().offset(self.profileCardVariant == .meet ? -16 : 0)
                make.height.equalTo(44)
            }
        } else {
            aboutLabel.snp.makeConstraints { make in
                make.leading.trailing.equalToSuperview().inset(16)
                make.top.equalTo(titleLabel.snp.bottom).offset(4)
                make.bottom.equalToSuperview().offset(self.profileCardVariant == .meet ? -16 : 0)
            }
        }
    }
}

UIViewRepresentable封装代码

struct ProfileAboutMeViewRepresentable: UIViewRepresentable {
    var profile: Profile

    func makeUIView(context: Context) -> ProfileAboutMeView {
        let view = ProfileAboutMeView(profile: profile)
        view.layoutView()
        return view
    }

    func updateUIView(_ uiView: ProfileAboutMeView, context: Context) {
        uiView.update(forProfile: profile)
    }
} 

SwiftUI中使用代码

ProfileAboutMeViewRepresentable(profile: viewModel.otherUser)
   .frame(maxWidth: .infinity, alignment: .leading)
   .frame(maxHeight: .infinity, alignment: .bottom)

问题排查与修复

以下是几个核心问题点及对应修复方案:

  • 手动调用layoutView干扰布局周期:
    在makeUIView中直接调用layoutView会打乱AutoLayout(尤其是SnapKit)的正常工作流程,SwiftUI会自动触发布局。
    修复:

    1. 删除makeUIView中的view.layoutView()调用
    2. 在ProfileAboutMeView中重写layoutSubviews,让系统自动触发布局:
      override func layoutSubviews() {
          super.layoutSubviews()
          layoutView()
      }
      
  • 缺少intrinsicContentSize导致SwiftUI无法计算尺寸:
    SwiftUI依赖UIKit视图的intrinsicContentSize来确定布局尺寸,未提供该值会导致视图被压缩到0。
    修复:在ProfileAboutMeView中重写该属性:

    override var intrinsicContentSize: CGSize {
        return systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    }
    
  • SwiftUI中的frame设置冲突:
    maxHeight: .infinity加底部对齐的设置会让SwiftUI无法正确识别视图的内容高度,导致视图被压缩。
    修复:简化frame设置,让SwiftUI尊重视图的内容尺寸:

    ProfileAboutMeViewRepresentable(profile: viewModel.otherUser)
        .frame(maxWidth: .infinity)
        .fixedSize(horizontal: false, vertical: true)
    
  • 检查父类ProfileCardGenericView的初始化:
    确保父类的init()方法设置了autoresizingMask = [],因为SwiftUI管理布局,不需要UIKit的自动调整:

    override init(frame: CGRect) {
        super.init(frame: frame)
        autoresizingMask = []
    }
    
    init() {
        super.init(frame: .zero)
        autoresizingMask = []
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:15:59