使用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会自动触发布局。
修复:- 删除
makeUIView中的view.layoutView()调用 - 在
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
相关产品推荐
相关产品推荐

