0

I am using GeometryReader to calculate the size of font to use to fit several lines of text, however it is always too big. What can be wrong with my calculation?

Here's a simply Playground

import SwiftUI
import PlaygroundSupport

struct MainView : View {
    
    var body: some View {
        VStack {
            SomeView()
                .frame(width: 508.0, height: 246.5)
        }
    }
}

struct SomeView: View {
    
    let newData = ["1", "2", "3", "4", "5", "6", "7", "8"]
    var lines: Int { newData.count }
    
    var body: some View {
        
        GeometryReader { geometry in
            VStack(alignment: .leading, spacing: 0) {
                ForEach(0..<lines) { idx in
                    Text(newData[idx])
                        .padding(0)
                }
            }
            .font(.system(size: geometry.size.height / CGFloat(lines)))
            .onAppear {
                print(geometry.size)
                print(lines)
                print(geometry.size.height / CGFloat(lines))
            }
        }
    }
}

PlaygroundPage.current.setLiveView(MainView())

This gives me this result: enter image description here

The GeometryReader correctly reports the height of the box to be 246.5 and the number of lines to be 8 which results in a 30.8125 font size.

It seems the font size needs some additional padding but how do I calculate this?

I want to be able to supply an unknown amount of data and have it fill the box. (Well I am actually using a LazyVGrid which is suffering the same issue).

Darren
  • 10,182
  • 20
  • 95
  • 162

1 Answers1

1

Font size is not equal to size this text takes on the screen. Check out this answer

You can get real line height with lineHeight from UIFont, and using this value you can calculate font size needed for your line height:

let expectedLineHeight = geometry.size.height / CGFloat(lines)
let fontSize = expectedLineHeight * expectedLineHeight / UIFont.systemFont(ofSize: expectedLineHeight).lineHeight
...
.font(.system(size: fontSize))
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220