我想创建一个文本视图内的圆形视图。字体大小应该自动设置为适合圆的大小。在 SwiftUI 中如何做到这一点?我试过 scaledTofill 和 scaledToFit 修饰符,但它们对 Text 视图没有影响:
struct ContentView : View { var body: some View { ZStack { Circle().strokeBorder(Color.red, lineWidth: 30) Text("Text").scaledToFill() } } }
要做到这一点,你不需要 ZStack。你可以添加一个背景到 Text:
ZStack
Text
Text("Text text text?") .padding() .background( Circle() .strokeBorder(Color.red, lineWidth: 10) .scaledToFill() .foregroundColor(Color.white) )
结果是:
一种可能的“黑客技术”是使用大字体和小比例因子,这样它就会缩小自己:
ZStack { Circle().strokeBorder(Color.red, lineWidth: 30) Text("Text") .padding(40) .font(.system(size: 500)) .minimumScaleFactor(0.01) } }
人们可以使用 GeometryReader为了使它也工作在景观模式。
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)) } }
这里有一个解决方案,它将调整文本大小的代码隐藏在一个自定义修饰符中,这个修饰符可以应用于任何视图,而不仅仅是一个圆,并接受一个指定文本应该占据的视图分数的参数。
(我不得不承认,虽然@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) } } }
使用这个修饰符,代码就变成了这样:
var body: some View { Circle().strokeBorder(Color.red, lineWidth: 30) .aspectRatio(contentMode: .fit) .overlay(Text("Text") .modifier(FitToWidth(fraction: fraction))) }
此外,当 Xcode 的未来版本提供了避免 .minimumScaleFactor黑客攻击的 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() } } }
看起来是这样的:
您希望允许您的文本:
您选择此比例因子限制以满足您的需要。通常情况下,您不会缩小到超出可读性或超出限制,这将使您的设计看起来很糟糕
struct ContentView : View { var body: some View { ZStack { Circle().strokeBorder(Color.red, lineWidth: 30) Text("Text") .scaledToFill() .minimumScaleFactor(0.5) .lineLimit(1) } }
}
我把@Simibac 和@Anton 的答案混合在一起,结果被 iOS14.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上遇到的问题。
frame(in:)
.midX
.midY
然后我在 View上设置了一个分机:
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()
基于@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)) } }
我的定时器也有同样的问题。不幸的是,计时器每秒钟改变一次文本,所以文本一直在跳来跳去,不断地上升和下降。 我的方法是计算,什么是可以显示的最长的计时器-在我的情况下“-44:44:44”-和50点大小将导致227.7点大帧。227除以50(我以前用过的点大小) ,每个点的宽度为4.5(向下舍入)。 小心: 1 pt 的大小给了我一个5.3点大的框架-所以越大的字体越接近实际的文本大小没有框架它得到。
因为我正在使用一个几何阅读器无论如何,我可以简单地设置一个固定的文本大小,使用
Text("-44:44:44") .font(.system(size: geometry.size.width / 4.5))
工作非常好,如果没有’-’或没有小时显示,我有一些空间的左边和右边,但文本不跳转。
这可以通过不同的比例因子进行细化,具体取决于所显示的数字数量,因此“-mm: ss”的另一个比例因子是。 当时间显示或隐藏时,这将导致“跳转”——但这很少发生在我需要的时候。
我有固定大小的按钮,这为我工作,以自动缩小长文本。
Text("This is a long label that will be scaled to fit:") .lineLimit(1) .minimumScaleFactor(0.5)
来源: 苹果