11

As of today's release of iOS 14.0 my iOS code, which depends heavily on GeometryReader for layout, is no longer working well. I.e, layout has been kind of randomized.

In the Xcode debugger I have compared the same code running on iOS 13.6 vs iOS 14.0 and see that the problem is that the GeometryProxy structure is not being initialized in iOS 14.0.

In the example code below the variable g, a GeometryProxy, has valid width and height values in iOS 13 but is all zero's in iOS 14. (This is just one of the simpler uses I make of GeometryProxy values -- I would appreciate if nobody points out the obvious fact that this snippet could be accomplished much more easily in another way.)

Is this a change to the GeometryReader or a bug? Anyone have a workaround? Did I make a huge mistake depending on GeometryReader for dynamic layout?

struct TextView: View {
  @EnvironmentObject var data: RecorderData
  let m = MusicalNote()

  var body: some View {
      GeometryReader { g in
          Stack(alignment: .leading) {
              Text(self.data.curNote.getString())
                 .font(.system(size: g.size.height / 2.4))
                 .padding(.bottom)
              Text(self.data.fdata.fingerings[self.data.curRecorder.id] ![self.data.curNote.seq] ![self.data.curFingType] ![self.data.currentFingeringChoice].comment)
                 .font(.headline)
        }
      Spacer()
    }
  }
}
Dávid Pásztor
  • 40,247
  • 8
  • 59
  • 80
lp1756
  • 726
  • 1
  • 6
  • 17
  • Any different behavior on system update worth submitting feedback, and the sooner is the better. – Asperi Sep 17 '20 at 16:26
  • Would you prepare minimal reproducible example? – Asperi Sep 17 '20 at 17:30
  • I tried doing a very simple example to reproduce this and found that with just one view or one view and one subview the GeometryProxy was being properly populated. I am going through my app code to see if I can find something that's different (aside from size and complexity) and if I can find that will add it to the example. – lp1756 Sep 17 '20 at 18:22
  • Is it possible that the GeometryProxy values are set in a separate thread? I ask this because it does seem that though the values are zero the first time through the view's code, if there is a data update which requires repainting the view, the values are set -- but sometimes not until the 2nd or 3rd time through, and it seems to vary. At any rate I am not able to reproduce this in a very simple example. It would be good to know if anyone else is experiencing the issue. – lp1756 Sep 17 '20 at 19:50
  • Same issue with me, anyone can help what happening? – Shahin ShamS Sep 20 '20 at 12:13

2 Answers2

7

It's definitely changed - this post sums it up: https://swiftui-lab.com/geometryreader-bug/

GeometryReader now lays out its content different to how it used to. It used to centre it horizontally and vertically in the parent but now it aligns it to the top-left.

My app looks awful - what's frustrating is it's not clear if this is new behaviour and is as-designed, or whether it's a bug and will be fixed. I'm trying to go through my app and manually apply offsets but the dynamic nature of layouts using GeometryReader means it is not always easy.

  • Thank you for this link. But I think there are two things going on here. The link you reference describes one problem -- the change in alignment. The problem I described is related to when the GeometryProxy values are filled in. I was seeing zeros in the proxy size parameters and have concluded that this was because I was calculating my dynamic sizings in .onAppear(). In iOS 13 the proxy size parameters were already set when .onAppear was called, but not in iOS 14. I have resolved my problem by moving my sizing calculations to the main body of the view instead of .onAppear(). – lp1756 Sep 20 '20 at 16:13
  • I share your frustration... what a bug. – ConfusionTowers Sep 22 '20 at 03:29
  • @lp1756 I was seeing a similar issue where the proxy values were 0 when I was trying to use them in .onAppear(). Although in your example it doesn't look like you were using .onAppear()? – bze12 Sep 23 '20 at 01:49
  • @bze12 you are right. In my example, when run in the debugger, the proxy values are zero with iOS 14 but good with iOS13 -- .onAppear() is not a factor in the example. All I know for sure is that in my app, when I moved the use of the proxy values from .onAppear to the body of the view, the app started correctly calculating the dynamic layout. I am still puzzled as to the exact nature of this bug/change -- but my app is now working (until they change something else in iOS 15!!) – lp1756 Sep 23 '20 at 12:31
1

Editing my previous answer as its now obviously bad advice

From https://developer.apple.com/documentation/xcode-release-notes/xcode-12-release-notes

Rebuilding against the iOS 14, macOS 11, watchOS 7, and tvOS 14 SDKs changes uses of GeometryReader to reliably top-leading align the views inside the GeometryReader. This was the previous behavior, except when it wasn’t possible to detect a single static view inside the GeometryReader. (59722992) (FB7597816)

Which says, to me at least, that the previous behaviour was buggy by their standards - despite it matching the conventions for other layout containers like VStack. And that this behaviour is the new normal.

Andrew Lipscomb
  • 716
  • 5
  • 15