Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get SwiftUI Text to clip instead of truncate with dots (...)

Tags:

ios

swiftui

In a SwiftUI view, I have several Text elements in a HStack. Depending on the user input there will not be horizontal room to show all of the texts. The HStack does it job fine by ensuring all of the Text elements get equal widths and the strings are truncated. This is all as expected and as it should be.

The problem is that all the strings are truncated with a "..." in the end whereas I want the behaviour of UILabel.lineBreakMode = .byClipping, that is the string should simply be cut off at the edge of the Text element.

How do I achieve this?

Edit for more details on what I want:

import SwiftUI

struct TextClipPoC: View {
    var body: some View {
        HStack {
            textElm
            textElm
            textElm
            textElm
        }
    }

    var textElm: some View {
        Text("abcdefghijklmn")
            .padding(.all, 3)
            .background(Color.yellow)
    }
}

struct TextClipPoC_Previews: PreviewProvider {
    static var previews: some View {
        TextClipPoC()
            .previewLayout(.fixed(width: 320, height: 40))
    }
}

gives this output: Default truncating behaviour

I want the exact same output as above, except instead of "..." I want the text to just clip.

If I just add .fixedSize() to the HStack (or to the Text elements), as suggested in a solution, I get this result: With fixed with

like image 592
Nicolai Henriksen Avatar asked Jul 05 '20 21:07

Nicolai Henriksen


2 Answers

One solution is to overlay two instances of the same Text, one fixed size and one normal, let the normal one decide the size and hide it and then have the fixed size one clipped.

Can be done with a ViewModfier:

struct FixedClipped: ViewModifier {
    func body(content: Content) -> some View {
        ZStack(alignment: .leading) {
            content.hidden().layoutPriority(1)
            content.fixedSize(horizontal: true, vertical: false)
        }
        .clipped()
    }
}

extension View {
    func fixedClipped() -> some View {
        self.modifier(FixedClipped())
    }
}

and then used like this:

struct TextClipPoC: View {
    var body: some View {
        HStack {
            textElm
            textElm
            textElm
        }
    }

    var textElm: some View {
        Text("abcdefghijklmn")
            .padding([.leading, .trailing], 3)
            .background(Color.yellow)
            .fixedClipped()
    }
}

struct TextClipPoC_Previews: PreviewProvider {
    static var previews: some View {
        TextClipPoC()
            .previewLayout(.fixed(width: 320, height: 40))
    }
}

This produces this result: Clipped text

like image 191
Nicolai Henriksen Avatar answered Oct 16 '22 22:10

Nicolai Henriksen


To avoid truncation it needs to use fixed size, like

HStack {

   ... your text items here     

}
.fixedSize()

everything else depends on context of usage and will require .clipped at some upper container.

Other possible solution is to use deactivated ScrollView, like

ScrollView(.horizontal) {
    HStack {

       ... your text items here     

    }
}.disabled(true)
like image 44
Asperi Avatar answered Oct 16 '22 21:10

Asperi