复杂视图中的SwiftUI字体缩放

时间:2019-10-20 16:06:48

标签: ios swift swiftui

我的目标是确保容器中的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))
        }

    }
}

结果:

Result

但是,当我们使用更复杂的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))
        }
    }
}

只需添加这三个修饰符:

.font(.system(size: 500)) .minimumScaleFactor(0.01) .lineLimit(1)

不会像第一个例子那样产生结果;文本超出框架。 我做得很成功,使用GeometryReader产生了想要的结果,然后根据geometry.size.width缩放了字体大小。这是在SwiftUI中获得理想结果的唯一方法吗?

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

您可以尝试使所有 Text 高度相同。为此,您需要明确设置内边距和间距,以便缩放而不是固定的默认值。

此外,Spacer() 在这里没有多大意义 - 如果要求所有 Text 保持相同的大小,Spacer 只会使 all< /em> 文字小。对于 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)
            }
        }
    }
}

结果:

Result