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

SwiftUI中Sheet内带AttributedString的Text不遵守lineLimit限制

SwiftUI中AttributedString在Sheet内无法突破lineLimit展开的问题解决

问题原因

  1. AttributedString布局缓存机制:SwiftUI对普通String和AttributedString的布局计算逻辑存在差异,尤其是从HTML转换而来的AttributedString,当lineLimit从固定值切换到nil时,布局系统未正确触发文本高度的重新计算,导致内容仍被截断。
  2. Sheet容器的布局约束:Sheet作为模态容器,内部ScrollView会给子视图带来额外的布局优先级限制,进一步阻碍了Text组件在lineLimit变化时更新自身尺寸。

可行解决方案

方案一:强制刷新Text布局(最简单有效)

通过给Text组件添加id修饰符,当isExpanded状态变化时,让SwiftUI重新创建Text实例,强制触发布局重新计算:

修改ExpandableAttributedText中的Text部分:

Text(attributedString)
    .lineLimit(isExpanded ? nil : maxLines)
    .textSelection(.enabled)
    .id(isExpanded) // 关键:状态变化时重建Text,刷新布局

同时,为Sheet内的ExpandableAttributedText添加宽约束,确保文本获得足够布局空间:

.sheet(isPresented: $showModel, content: {
    ScrollView{
        ExpandableAttributedText(string: text, maxLines: 4)
            .padding()
            .frame(maxWidth: .infinity, alignment: .leading) // 占满可用宽度
    }
})

方案二:用UIKit的UILabel包装(适配复杂富文本)

如果方案一仍存在布局异常,可通过UIViewRepresentable封装UILabel,直接控制行数,规避SwiftUI的布局bug:

struct AttributedText: UIViewRepresentable {
    let attributedString: NSAttributedString
    var lineLimit: Int?
    
    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.numberOfLines = lineLimit ?? 0
        label.attributedText = attributedString
        label.lineBreakMode = .byWordWrapping
        return label
    }
    
    func updateUIView(_ uiView: UILabel, context: Context) {
        uiView.numberOfLines = lineLimit ?? 0
        uiView.attributedText = attributedString
    }
}

随后修改ExpandableAttributedText的body部分:

VStack(alignment: .leading, spacing: 8) {
    AttributedText(
        attributedString: attributedString as NSAttributedString,
        lineLimit: isExpanded ? nil : maxLines
    )
    
    Button(action: {
        isExpanded.toggle()
    }) {
        Text(isExpanded ? "Show Less" : "Show More")
            .font(.caption)
            .foregroundColor(.primary)
    }
}

方案三:调整ScrollView的安全区域适配(可选)

若Sheet内的ScrollView约束影响布局,可尝试忽略安全区域:

.sheet(isPresented: $showModel, content: {
    ScrollView{
        ExpandableAttributedText(string: text, maxLines: 4)
            .padding()
    }
    .edgesIgnoringSafeArea(.all)
})

验证效果

修改后,无论是主界面还是Sheet内的文本,点击"Show More"都会正确展开全部内容,点击"Show Less"则会回到指定行数限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 11:37:26