复杂视图中的 SwiftUI 字体缩放
Posted
技术标签:
【中文标题】复杂视图中的 SwiftUI 字体缩放【英文标题】:SwiftUI Font scaling in a complex View 【发布时间】:2019-10-20 16:06:48 【问题描述】:我的目标是确保容器中的文本能够根据其父级进行缩放。当容器只包含一个 Text 视图时效果很好,如下所示:
import SwiftUI
struct FontScalingExperiment: View
var body: some View
Text("Hello World ~!")
.font(.system(size: 500))
.minimumScaleFactor(0.01)
.lineLimit(1)
.padding()
.background(
RoundedRectangle(cornerRadius: 20)
.fill(Color.yellow)
.scaledToFill()
)
struct FontScalingExperiment_Previews: PreviewProvider
static var previews: some View
Group
FontScalingExperiment()
.previewLayout(.fixed(width: 100, height: 100))
FontScalingExperiment()
.previewLayout(.fixed(width: 200, height: 200))
FontScalingExperiment()
.previewLayout(.fixed(width: 300, height: 300))
FontScalingExperiment()
.previewLayout(.fixed(width: 400, height: 400))
结果:
但是,当我们有更复杂的 View 时,我们不能使用相同的方法来根据其父大小自动缩放文本,例如:
import SwiftUI
struct IndicatorExperiment: View
var body: some View
VStack
HStack
Text("Line 1")
Spacer()
Spacer()
VStack
Text("Line 2")
Text("Line 3")
Spacer()
Text("Line 4")
.padding()
.background(
RoundedRectangle(cornerRadius: 20)
.fill(Color.yellow)
)
.aspectRatio(1, contentMode: .fit)
struct IndicatorExperiment_Previews: PreviewProvider
static var previews: some View
Group
IndicatorExperiment()
.previewLayout(.fixed(width: 100, height: 100))
IndicatorExperiment()
.previewLayout(.fixed(width: 200, height: 200))
IndicatorExperiment()
.previewLayout(.fixed(width: 300, height: 300))
IndicatorExperiment()
.previewLayout(.fixed(width: 400, height: 400))
只需添加这 3 个修饰符:
.font(.system(size: 500))
.minimumScaleFactor(0.01)
.lineLimit(1)
不会像第一个例子那样产生结果;文本放大超出框架。
我成功了,使用 GeometryReader 产生了我想要的结果,然后根据geometry.size.width
缩放字体大小。这是在 SwiftUI 中实现预期结果的唯一方法吗?
【问题讨论】:
我有您遇到的确切问题,但我无法在任何地方找到答案。在我将视图放入 HStack 之前,一切都按预期工作。您介意与 GeometryReader 分享您的解决方案吗? GeometryReader 为我们提供了框架的高度和宽度,使用这个大小我们可以相应地设置字体。例如:GeometryReader g in HStack ... .font(.system(size: g.size.width / ratio)) ratio 是任意数字,来调整大小。需要进行手动视觉验证以确保它为您的最小帧正确渲染。 您的解决方案运行良好。目视检查是关键。谢谢分享。 【参考方案1】:您可以尝试使所有Text
s 高度相同。为此,您需要明确设置填充和间距,因此这将缩放而不是固定的默认值。
此外,Spacer()
在这里没有多大意义 - 如果要求所有 Text
保持相同大小,Spacer
只会使 all 文本变小.对于Text
根据空间进行缩放,而Spacer
试图使用尽可能多的空间,这是一个矛盾。相反,我决定只在初始化程序中设置VStack
的spacing
。
工作代码:
struct IndicatorExperiment: View
private let size: CGFloat
private let padding: CGFloat
private let primarySpacing: CGFloat
private let secondarySpacing: CGFloat
private let textHeight: CGFloat
init(size: CGFloat)
self.size = size
padding = size / 10
primarySpacing = size / 15
secondarySpacing = size / 40
let totalHeights = size - padding * 2 - primarySpacing * 2 - secondarySpacing
textHeight = totalHeights / 4
var body: some View
VStack(spacing: primarySpacing)
HStack
scaledText("Line 1")
Spacer()
.frame(height: textHeight)
VStack(spacing: secondarySpacing)
scaledText("Line 2")
scaledText("Line 3")
.frame(height: textHeight * 2 + secondarySpacing)
scaledText("Line 4")
.padding(padding)
.background(
RoundedRectangle(cornerRadius: 20)
.fill(Color.yellow)
)
.aspectRatio(1, contentMode: .fit)
.frame(width: size, height: size)
private func scaledText(_ content: String) -> some View
Text(content)
.font(.system(size: 500))
.minimumScaleFactor(0.01)
.lineLimit(1)
.frame(height: textHeight)
要测试的代码:
struct ContentView: View
var body: some View
ScrollView
VStack(spacing: 50)
IndicatorExperiment(size: 100)
IndicatorExperiment(size: 200)
IndicatorExperiment(size: 300)
IndicatorExperiment(size: 400)
结果:
【讨论】:
【参考方案2】:使用GeometryReader
和.minimumScaleFactor
修饰符可能是缩放视图中文本的唯一方法。要对大小进行更多控制,一种可能的方法是从父视图中提供 .frame
大小。
可缩放的文本视图
GeometryReader geo in
Text("Foo")
.font(
.system(size: min(geo.size.height, geo.size.width) * 0.95))
.minimumScaleFactor(0.05)
.lineLimit(1)
使用可缩放文本视图的父视图
GeometryReader geo in
ScaleableText()
.frame(width: geo.size.width, height: geo.size.height)
【讨论】:
以上是关于复杂视图中的 SwiftUI 字体缩放的主要内容,如果未能解决你的问题,请参考以下文章