Search code examples
iosswiftstringswiftui

SwiftUI: How can I limit a string to be displayed as one line, and support automatic scaling to a specified ratio, sliding to view the full text


How can I limit a string to be displayed as one line, and support automatic scaling to a specified ratio, and support sliding to view the full text without being truncated in SwiftUI

problem

(1).minimumScaleFactor(0.3) // doesn't work

(2)text is being truncated // hope it won't be truncated

Here is the code


import SwiftUI

struct ContentView: View {

@State private var text = "In the scrollview of SwiftUI, I have a very long string, which is limited to one line, and automatically scaled to the specified ratio, and can slide to display the full content without being truncated"

var body: some View {
    VStack {
        ScrollView(.horizontal){
            Text(text)
                .font(.system(size: 80))
                .lineLimit(1)
                .minimumScaleFactor(0.3)
        }
        Text("this is another text")
    }
}

}


simulator image

The string to be displayed as one line, and support automatic scaling to a specified ratio, and support sliding to view the full text without being truncated in SwiftUI.


Solution

  • EDIT: revised to use ViewThatFits and a hidden footprint.


    So if I understand correctly...

    • you would like the text to be displayed as large as possible in the space available
    • as soon as there is too much text for the space available, the font size should begin to shrink so that it still fits into the space available if possible
    • once it has reached minimum size, it should be possible to scroll the text in order to see the rest of the line, without it being truncated.

    The problem you were having in your example is that the ScrollView disables the scaling.

    One way to solve is to use a hidden version of the text to establish a footprint:

    • The hidden version is not wrapped in a ScrollView, so it will be truncated if it is very long and cannot be scaled any further.
    • The visible version of the text is then shown in an overlay.
    • The overlay is constrained by the height of the base view, so the text in the overlay is forced to shrink to the same size as in the base view.
    • ViewThatFits is used to show the text without a ScrollView (if it fits) or with a ScrollView (if it doesn't).

    By using ViewThatFits, the text is only wrapped with a ScrollView if it needs to be. This prevents a short text from moving when it is "pushed", because there will be no ScrollView around it.

    private let longText = "In the scrollview of SwiftUI, I have a very long string, which is limited to one line, and automatically scaled to the specified ratio, and can slide to display the full content without being truncated"
    
    private func formattedText(key: String) -> some View {
        Text(LocalizedStringKey(key))
            .font(.system(size: 80))
            .lineLimit(1)
            .minimumScaleFactor(0.3)
    }
    
    private func textLine(_ key: String) -> some View {
        formattedText(key: key)
            .hidden()
            .overlay(
                ViewThatFits(in: .horizontal) {
                    formattedText(key: key)
                    ScrollView(.horizontal) {
                        formattedText(key: key)
                    }
                }
            )
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            textLine(longText)
            textLine("this is another text")
        }
    }
    

    text line