SwiftUI: Как создать однострочную этикетку, которая сжимается при вертикальном сжатии? - PullRequest
0 голосов
/ 01 августа 2020

Как создать однострочную этикетку, уменьшающую размер шрифта при вертикальном сжатии?

Естественный выбор сочетания minimumScaleFactor с lineLimit дает неожиданные результаты.

См. этот пример. Без ограничения строки этикетка сжимается по вертикали и правильно регулирует размер шрифта. Добавление .lineLimit(1) предотвращает уменьшение размера шрифта верхней метки.

import SwiftUI

struct ContentView: View {
    let text:String
    
    var body: some View {
        VStack(alignment:.center, spacing:0 ) {
            Text(self.text)
                .font(Font.system(size: 60.0))
                .minimumScaleFactor(0.15)
                .background(Color.blue)
            
            Rectangle()
                .strokeBorder()
                .foregroundColor(Color.red)
                .frame(maxWidth: .infinity)
                .frame(height:60.0)
        }
        .frame(width: 100, height: 100)
        .background(Color.green)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        VStack(spacing:20) {
            ContentView(text:"A quick brown fox")
                .lineLimit(1)
            Text("Line limit 1")

            ContentView(text:"150")
                .lineLimit(1)
            Text("Line limit 1")

            ContentView(text:"A quick brown fox")
            Text("No line limit")

            ContentView(text:"150")
            Text("No line limit")
        }
        
    }
}

введите описание изображения здесь

Ответы [ 3 ]

0 голосов
/ 02 августа 2020

Используйте .lineLimit на месте, как показано ниже (проверено с Xcode 12)

демо

struct ContentView: View {
    let text:String

    var body: some View {
        VStack(alignment:.center, spacing:0 ) {
            Text(self.text)
                .font(Font.system(size: 60.0))
                .lineLimit(text.count > 4 ? 1 : nil)       // << here !!
                .minimumScaleFactor(0.15)
                .background(Color.blue)

            Rectangle()
                .strokeBorder()
                .foregroundColor(Color.red)
                .frame(maxWidth: .infinity)
                .frame(height:60.0)
        }
        .frame(width: 100, height: 100)
        .background(Color.green)
    }
}
0 голосов
/ 03 августа 2020

Вот лучший обходной путь, который я мог придумать, не предполагающий длину строки.

Используйте GeometryReader, чтобы явно масштабировать размер шрифта метки в зависимости от известной высоты ее контейнера. minimumScaleFactor продолжает заботиться о масштабировании текста по горизонтали. Немного уродливо, так как вы должны знать высоту метки для размера шрифта по умолчанию. В моем приложении этого достаточно.

Пожалуйста, ответьте, если у вас есть лучший ответ! ?

GeometryReader {reader in
    Text(self.text)
        .font(Font.system(size: 60.0 * reader.size.height / 80))
        .minimumScaleFactor(0.15)
        .lineLimit(1)
        .background(Color.blue)
}

Пример полного интерактивного взаимодействия:

https://gist.github.com/mikebernardo/011d9f6839baac40b359e0ad18b4b0d4

0 голосов
/ 01 августа 2020

Кажется, что Text занимает больше места, чем должен, и толкает Rectangle вниз. попробуйте ограничить высоту Text, установив frame со значением maxHeight, чтобы ограничить его height.

struct ContentView: View {
    let text:String
    
    var body: some View {
        VStack(alignment:.center, spacing:0 ) {
            Text(self.text)
                .font(Font.system(size: 60.0))
                .minimumScaleFactor(0.15)
                .background(Color.blue)
                .frame(maxHeight: 40)
            
            
            Rectangle()
                .strokeBorder()
                .foregroundColor(Color.red)
                .frame(maxWidth: .infinity)
                .frame(height:60.0)
        }
        .frame(width: 100, height: 100)
        .background(Color.green)
    }
}
...