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

时间:2019-07-15 08:15:24

标签: swift swiftui

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

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

8 个答案:

答案 0 :(得分:11)

您要允许您的文字:

  • 缩小到特定限制
  • 在1条(或多条)线路上

您可以选择此比例因子限制来满足您的需求。通常,您不会缩小到可读性或限制之外,否则会使您的设计看起来很糟糕

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

}

答案 1 :(得分:8)

我必须同意,尽管@szemian的解决方案仍然不理想,但由于其他固有的问题,她的方法似乎是我们可以使用当前SwiftUI实现执行的最佳方法。 (@simibac的答案要求在文本或其属性(字体,粗细等)发生更改时,必须努力寻找一个新的幻数来替换0.4,并且@ giuseppe-sapienza不允许圆的大小只能指定文字的字体大小。)

这是一种解决方案,它在自定义修饰符中隐藏了文本调整大小的代码,该修饰符可以应用于任何View,而不仅仅是一个Circle,并采用一个参数指定该文本应占据的View的比例。

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)
        }
    }
}

使用修饰符,代码就是这样:

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

此外,当将来的Xcode版本提供SwiftUI改进以消除.minimumScaleFactor hack时,您只需更新修饰符代码即可使用它。 :)

如果您想了解分数参数的工作原理,以下代码可让您使用滑块进行交互式调整:

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()
        }
    }
}

是这样的:

Code running on iPhone X

答案 2 :(得分:2)

一个人可以使用INFO: Closed connection [connectionId{localValue:2}] to 127.0.0.1:27017 because there was a socket exception raised by this connection. Exception in thread "main" com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='DM', source='Admin', password=<hidden>, mechanismProperties=<hidden>} 使其也可以在横向模式下工作。

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

GeometryReader

enter image description here enter image description here

答案 3 :(得分:2)

我混合使用@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)
        }
    }
}

正如您所看到的,我使用了几何代理的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))
    }
}

所以用法是这样的:

Text("Your text")
    .fitSystemFont()

答案 4 :(得分:1)

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

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

    Text("Text")
        .padding(40)
        .font(.system(size: 500))
        .minimumScaleFactor(0.01)
     }
}

答案 5 :(得分:1)

基于@JaimeeAz 的回答。添加了指定最小字体的选项。

import SwiftUI

public struct FitSystemFont: ViewModifier {
    public var lineLimit: Int?
    public var fontSize: CGFloat?
    public var minimumScaleFactor: CGFloat
    public var percentage: CGFloat

    public func body(content: Content) -> some View {
        GeometryReader { geometry in
            content
                .font(.system(size: min(min(geometry.size.width, geometry.size.height) * percentage, fontSize ?? CGFloat.greatestFiniteMagnitude)))
                .lineLimit(self.lineLimit)
                .minimumScaleFactor(self.minimumScaleFactor)
                .position(x: geometry.frame(in: .local).midX, y: geometry.frame(in: .local).midY)
        }
    }
}

public extension View {
    func fitSystemFont(lineLimit: Int? = nil, fontSize: CGFloat? = nil, minimumScaleFactor: CGFloat = 0.01, percentage: CGFloat = 1) -> ModifiedContent<Self, FitSystemFont> {
        return modifier(FitSystemFont(lineLimit: lineLimit, fontSize: fontSize, minimumScaleFactor: minimumScaleFactor, percentage: percentage))
    }
}

答案 6 :(得分:0)

要实现此目的,您不需要ZStack。您可以为Text添加背景:

Text("Text text text?")
    .padding()
    .background(
       Circle()
          .strokeBorder(Color.red, lineWidth: 10)
          .scaledToFill()
          .foregroundColor(Color.white)
    )

结果是这样的: enter image description here

答案 7 :(得分:-1)

对我来说效果出奇的便宜的厚皮

struct ContentView: View {

var scale = UIScreen.main.bounds.width*0.08

var body: some View {
Text("something").font(.system(size: scale))
}}