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

SwiftUI中如何判断Text是否达到lineLimit()限制?

实现带行限制判断的Text视图(无需GeometryReader)

要实现限制3行的Text,超出时显示展开按钮,核心是准确判断文本是否被行限制截断。这里提供一种基于文本自身渲染高度对比的方案,无需依赖GeometryReader读取父布局尺寸:

核心思路

通过对比无限制行数的文本高度和限制行数后的文本高度,如果前者大于后者,说明文本被截断(超出3行),此时显示展开/收起按钮。我们用SwiftUI的PreferenceKey来传递两个文本的高度值,避免直接嵌套GeometryReader带来的布局依赖。

完整代码实现

struct TruncatableText: View {
    let text: String
    let lineLimit: Int
    @State private var isExpanded = false
    @State private var isTruncated = false
    
    var body: some View {
        VStack(alignment: .leading) {
            // 主显示文本,根据展开状态切换行限制
            Text(text)
                .lineLimit(isExpanded ? nil : lineLimit)
                // 隐藏的无限制文本,计算完整高度
                .background(
                    Text(text)
                        .lineLimit(nil)
                        .background(GeometryReader { proxy in
                            Color.clear.preference(key: FullTextHeightKey.self, value: proxy.size.height)
                        })
                        .hidden()
                )
                // 计算当前显示状态下的文本高度
                .background(GeometryReader { proxy in
                    Color.clear.preference(key: TruncatedTextHeightKey.self, value: proxy.size.height)
                })
                // 对比高度判断是否截断
                .onPreferenceChange(FullTextHeightKey.self) { fullHeight in
                    if let truncatedHeight = TruncatedTextHeightKey.value {
                        isTruncated = fullHeight > truncatedHeight
                    }
                }
            
            // 只有文本被截断时才显示按钮
            if isTruncated {
                Button(isExpanded ? "收起" : "展开") {
                    isExpanded.toggle()
                }
                .font(.caption)
                .foregroundColor(.blue)
            }
        }
    }
}

// 自定义PreferenceKey,用于传递完整文本高度
private struct FullTextHeightKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

// 自定义PreferenceKey,用于传递截断后文本高度
private struct TruncatedTextHeightKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

使用示例

struct ContentView: View {
    let shortText = "这是一段短文本,不会超过3行。"
    let longText = "这是一段很长的文本,用来测试行限制功能。这是一段很长的文本,用来测试行限制功能。这是一段很长的文本,用来测试行限制功能。这是一段很长的文本,用来测试行限制功能。这是一段很长的文本,用来测试行限制功能。"
    
    var body: some View {
        VStack(spacing: 20) {
            TruncatableText(text: shortText, lineLimit: 3)
            TruncatableText(text: longText, lineLimit: 3)
        }
        .padding()
    }
}

方案优势

  • 完全基于文本自身的渲染状态判断,不依赖父视图尺寸,适配所有字体、字号和屏幕尺寸。
  • 逻辑直观,通过高度差准确判断文本是否被截断,避免了GeometryReader可能带来的布局冲突。
  • 代码模块化,自定义视图可以直接复用在任何场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 12:10:53