【问题标题】:SwiftUI Font scaling in a complex View复杂视图中的 SwiftUI 字体缩放
【发布时间】: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 是任意数字,来调整大小。需要进行手动视觉验证以确保它为您的最小帧正确渲染。
  • 您的解决方案运行良好。目视检查是关键。谢谢分享。

标签: ios swift swiftui


【解决方案1】:

您可以尝试使所有Texts 高度相同。为此,您需要明确设置填充和间距,因此这将缩放而不是固定的默认值。

此外,Spacer() 在这里没有多大意义 - 如果要求所有 Text 保持相同大小,Spacer 只会使 all 文本变小.对于Text 根据空间进行缩放,而Spacer 试图使用尽可能多的空间,这是一个矛盾。相反,我决定只在初始化程序中设置VStackspacing

工作代码:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-06
      • 2014-01-15
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      相关资源
      最近更新 更多