如何使用SwiftUI缩放文本以适合父视图?

G. *_*arc 1 swift swiftui

我想在圆形视图内创建一个文本视图。字体大小应自动设置为适合圆圈的大小。如何在SwiftUI中完成?我尝试过scaledToFill和scaledToFit修饰符,但它们对Text视图没有影响:

struct ContentView : View {
    var body: some View {
        ZStack {
            Circle().strokeBorder(Color.red, lineWidth: 30)
            Text("Text").scaledToFill()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

sim*_*bac 40

可以使用GeometryReader以使其也可以在横向模式下工作。

它首先检查宽度或高度是否更小,然后根据这些中的较小者调整字体大小。

GeometryReader{g in
    ZStack {
        Circle().strokeBorder(Color.red, lineWidth: 30)
        Text("Text")
            .font(.system(size: g.size.height > g.size.width ? g.size.width * 0.4: g.size.height * 0.4))
    }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明

  • 那“min(g.size.height, g.size.width) * scale”呢? (7认同)

Gra*_*eph 27

您希望允许您的文本:

  • 缩小到一定限度
  • 在 1 个(或多个)行上

您可以选择此比例因子限制以满足您的需要。通常,您不会缩小超出可读性或超出限制,这将使您的设计看起来很糟糕

struct ContentView : View {
var body: some View {
    ZStack {
        Circle().strokeBorder(Color.red, lineWidth: 30)
        Text("Text")
            .scaledToFill()
            .minimumScaleFactor(0.5)
            .lineLimit(1)
    }
}
Run Code Online (Sandbox Code Playgroud)

}

  • 作品。请注意,iOS 16 不需要scaledToFill。 (3认同)

Ond*_*j H 22

我有固定大小的按钮,这对我来说可以自动缩小长文本。

Text("This is a long label that will be scaled to fit:")
    .lineLimit(1)
    .minimumScaleFactor(0.5)
Run Code Online (Sandbox Code Playgroud)

来源:苹果


Ant*_*ton 11

这是一个将文本调整代码隐藏在自定义修饰符中的解决方案,该修饰符可以应用于任何视图,而不仅仅是圆形,并采用一个参数指定文本应占据的视图的分数。

(我必须同意,虽然@szemian 的解决方案仍然不理想,但由于其他方法固有的问题,她的方法似乎是我们对当前 SwiftUI 实现所能做的最好的方法。@simibac 的答案需要摆弄以找到一个新的幻数每当文本或其属性(字体、粗细等)发生更改时,请替换 0.4,并且@giuseppe-sapienza 不允许指定圆圈的大小,仅允许指定文本的字体大小。)

struct FitToWidth: ViewModifier {
    var fraction: CGFloat = 1.0
    func body(content: Content) -> some View {
        GeometryReader { g in
        content
            .font(.system(size: 1000))
            .minimumScaleFactor(0.005)
            .lineLimit(1)
            .frame(width: g.size.width*self.fraction)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用修饰符,代码变成这样:

    var body: some View {
        Circle().strokeBorder(Color.red, lineWidth: 30)
            .aspectRatio(contentMode: .fit)
            .overlay(Text("Text")
                .modifier(FitToWidth(fraction: fraction)))
    }
Run Code Online (Sandbox Code Playgroud)

此外,当 Xcode 的未来版本提供 SwiftUI 改进以消除.minimumScaleFactor黑客攻击时,您只需更新修改器代码即可使用它。:)

如果您想查看分数参数的工作原理,请使用以下代码,让您使用滑块以交互方式调整它:

struct ContentView: View {

    @State var fraction: CGFloat = 0.5

    var body: some View {
        VStack {
            Spacer()
            Circle().strokeBorder(Color.red, lineWidth: 30)
                .aspectRatio(contentMode: .fit)
                .overlay(Text("Text")
                .modifier(FitToWidth(fraction: fraction)))
            Slider(value: $fraction, in:0.1...0.9, step: 0.1).padding()
            Text("Fraction: \(fraction, specifier: "%.1f")")
            Spacer()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它的样子:

在 iPhone X 上运行的代码


Jai*_*eAz 8

我混合了 @Simibac 和 @Anton 的答案,但被 iOS 14.0 破坏了,所以这就是我修复它的方法。也应该适用于 SwiftUI 1.0。

struct FitSystemFont: ViewModifier {
    var lineLimit: Int
    var minimumScaleFactor: CGFloat
    var percentage: CGFloat

    func body(content: Content) -> some View {
        GeometryReader { geometry in
            content
                .font(.system(size: min(geometry.size.width, geometry.size.height) * percentage))
                .lineLimit(self.lineLimit)
                .minimumScaleFactor(self.minimumScaleFactor)
                .position(x: geometry.frame(in: .local).midX, y: geometry.frame(in: .local).midY)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我使用几何代理的frame(in:)方法来获取本地坐标空间,然后使用.midX.midY使其正确居中,因为正确居中是我在 iOS 14 上遇到的问题。

然后我在以下位置设置了扩展View

extension View {
    func fitSystemFont(lineLimit: Int = 1, minimumScaleFactor: CGFloat = 0.01, percentage: CGFloat = 1) -> ModifiedContent<Self, FitSystemFont> {
        return modifier(FitSystemFont(lineLimit: lineLimit, minimumScaleFactor: minimumScaleFactor, percentage: percentage))
    }
}
Run Code Online (Sandbox Code Playgroud)

所以用法是这样的:

Text("Your text")
    .fitSystemFont()
Run Code Online (Sandbox Code Playgroud)


sze*_*ian 6

一种可能的“破解”是使用较大的字体大小和较小的缩放比例,以使其自身收缩:

ZStack {
    Circle().strokeBorder(Color.red, lineWidth: 30)

    Text("Text")
        .padding(40)
        .font(.system(size: 500))
        .minimumScaleFactor(0.01)
     }
}
Run Code Online (Sandbox Code Playgroud)

  • 从XCode 11 Beta 6开始,如果文本不适合当前宽度,则文本会自动换行。因此,您需要将.lineLimit(1)添加到Text元素以使其再次起作用。 (3认同)
  • 使用该解决方案进行更多测试,我注意到文本并未在所有长宽比上精确缩放。这是因为文本视图不是方形的。我可以通过在 ZStack 视图中添加“aspectRatio”修饰符来解决这个问题: .aspectRatio(1, contentMode: .fit) (2认同)