繁体   English   中英

SwiftUI - 如何知道文本中的行数?

[英]SwiftUI - how know number of lines in Text?

我有一个动态文本,它可以大可小,默认情况下只显示 3 行,并且仅在需要时添加“更多”按钮。 当用户点击此按钮(“更多”)时 - 我将显示所有测试。

我问,如何在 SwiftUI 中知道文本是否超过 3 行?

您可以使用GeometryReader来确定文本字段的宽度,然后将其与有关字体的信息一起使用来计算显示整个文本所需的边界矩形的大小。 如果该高度超过文本视图,那么我们知道文本已被截断。

struct LongText: View {

    /* Indicates whether the user want to see all the text or not. */
    @State private var expanded: Bool = false

    /* Indicates whether the text has been truncated in its display. */
    @State private var truncated: Bool = false

    private var text: String

    init(_ text: String) {
        self.text = text
    }

    private func determineTruncation(_ geometry: GeometryProxy) {
        // Calculate the bounding box we'd need to render the
        // text given the width from the GeometryReader.
        let total = self.text.boundingRect(
            with: CGSize(
                width: geometry.size.width,
                height: .greatestFiniteMagnitude
            ),
            options: .usesLineFragmentOrigin,
            attributes: [.font: UIFont.systemFont(ofSize: 16)],
            context: nil
        )

        if total.size.height > geometry.size.height {
            self.truncated = true
        }
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text(self.text)
                .font(.system(size: 16))
                .lineLimit(self.expanded ? nil : 3)
                // see https://swiftui-lab.com/geometryreader-to-the-rescue/, 
                // and https://swiftui-lab.com/communicating-with-the-view-tree-part-1/
                .background(GeometryReader { geometry in
                    Color.clear.onAppear {
                        self.determineTruncation(geometry)
                    }
                })

            if self.truncated {
                self.toggleButton
            }
        }
    }

    var toggleButton: some View {
        Button(action: { self.expanded.toggle() }) {
            Text(self.expanded ? "Show less" : "Show more")
                .font(.caption)
        }
    }

}

这就是它查找长文本和短文本的方式:

使用示例预览

希望这可以帮助。

基于 bhuemer 的出色工作,此版本尊重 SwiftUI 的本地字体,而不需要硬编码的 UIFont。 这不是使用 String 布局读取“完整”文本的大小,而是将 Text 呈现三次:一次是真实的,一次有行限制,一次没有行限制。 然后它使用两个 GR 来比较最后两个。

struct LongText: View {

    /* Indicates whether the user want to see all the text or not. */
    @State private var expanded: Bool = false

    /* Indicates whether the text has been truncated in its display. */
    @State private var truncated: Bool = false

    private var text: String

    var lineLimit = 3

    init(_ text: String) {
        self.text = text
    }

    var body: some View {
        VStack(alignment: .leading) {
            // Render the real text (which might or might not be limited)
            Text(text)
                .lineLimit(expanded ? nil : lineLimit)

                .background(

                    // Render the limited text and measure its size
                    Text(text).lineLimit(lineLimit)
                        .background(GeometryReader { displayedGeometry in

                            // Create a ZStack with unbounded height to allow the inner Text as much
                            // height as it likes, but no extra width.
                            ZStack {

                                // Render the text without restrictions and measure its size
                                Text(self.text)
                                    .background(GeometryReader { fullGeometry in

                                        // And compare the two
                                        Color.clear.onAppear {
                                            self.truncated = fullGeometry.size.height > displayedGeometry.size.height
                                        }
                                    })
                            }
                            .frame(height: .greatestFiniteMagnitude)
                        })
                        .hidden() // Hide the background
            )

            if truncated { toggleButton }
        }
    }

    var toggleButton: some View {
        Button(action: { self.expanded.toggle() }) {
            Text(self.expanded ? "Show less" : "Show more")
                .font(.caption)
        }
    }
}

下面显示了周围视图的行为。 请注意,这种方法支持LongText(...).font(.largeTitle)就像普通文本一样。

struct ContentView: View {
    let longString = "This is very long text designed to create enough wrapping to force a More button to appear. Just a little more should push it over the edge and get us to one more line."

    var body: some View {
        VStack {
            Text("BEFORE TEXT")
            LongText(longString).font(.largeTitle)
            LongText(longString).font(.caption)
            Text("AFTER TEXT")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

显示大标题文本的“更多”按钮,但标题文本没有“更多”按钮的预览屏幕截图。

下面是一个例子:

struct TextDemo: View {

    @State var moreText = true

    var body: some View {
        Group {
            Button(action: { self.moreText.toggle()} ) { Text("More") }
            Text("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello")
                .frame(width: 300)
                .lineLimit( moreText ? 3: nil)
         }
     }
}

这没有帮助,但我认为您应该找到离屏渲染的方法。 我找不到这个,但为了正确计算 LazyHGrid 中水平行中行的高度,我需要做同样的:(

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM