NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: Issues with image spacing and maybe GeometryReader

Forums > SwiftUI

I'm working on my Clockinator app again and I've run into a curious issue. Here's a picture that's worth at least 100 words:

Shown here are 2 clocks, both in Portrait and in Landscape on the iPad (9th Gen) simulator. This behavior is the same on real iPads and iPhones.

The clock usually displays just the digits, but has the option of displaying some kind of animation for the "second hand".

On the left, in the clown clock, there're clown cars that go back and forth. It's simply another view that has 4 images that have x coordinates that change. It doesn't use GeometryReader, so it's a little different on different size iPads or the phone, but it's good enough to get the job done.

On the right is the princess clock. the second hand is a view with 6 rainbows that grow incrementally, using path.addArc(with_some_creative_math_in_here). Because the rainbows have to go precisely edge to edge, I've tried to use GeometryReader to get sizing information so I can make the math work out for the addArc call. (Not pictured, but planned are the unicorns that go with the rainbows.)

On both clocks, you can see some outlines, that's just some debugging borders I put in to help me visualize what's going on.

The issue is that the princess clock numbers retreat really high up the screen, while the clown clock numbers behave like the other 23 clock faces in Clockinator. Something is making the rainbow view grab way more space than it needs, which I can see on the Landscape clock because I stare at the faces all day, but it really stands out in the Portrait Orientation. Again the only difference I can find is that I'm using GeometryReader on the princess rainbows.

What can I do to make the GeometryReader less grabby? In a perfect world the 6:57 in both clocks would take up the same space and size as the one clown clock on the left. The raibows in the princess clock are generated, whereas the clown cars are .pngs, but they are relatively the same size and the difference doesn't seem like it should be this great. So how can I fix it?

The clock digits are both displayed by the same view, and the clown cars/rainbow seconds displays are each a separate view that are displayed conditionally in a VStack below the clock digits' HStack.

Here's the code that conditionally calls the seconds views. it's at the bottom of a VStack that inlcludes the clock digits.

switch currentFace {
    case .circus, .toronto, .winter:
        if settings.showSeconds {
            ScrollingSecondsView(settings: settings)
                .opacity(settings.showSeconds ? 1 : 0)
                .animation(
                    Animation.easeInOut(duration: 1.0)
                )
        }
    case .clowns:
        if settings.showSeconds {
            ClownCarSecondsView(settings: settings)
                .opacity(settings.showSeconds ? 1 : 0)
                .animation(
                    Animation.easeInOut(duration: 1.0)
                )
                .border(settings.showBorder ? Color.subwayAvocado : .clear, width: 0.5)
        }
    case .princess:
        if settings.showSeconds {
            SecondsUnicornView(settings: settings)
                .animation(
                    Animation.easeInOut(duration: 1.0)
                )
        }
    default:
        SecondsView(mySize: 5, palette: palette, settings: settings)
            .offset(self.faceOffset)
            .opacity(settings.showSeconds ? 1 : 0)
            .animation(
                Animation.easeInOut(duration: 1.0)
            )
}

any help or suggestions or ideas are greatly appreciated. Because of the excess space created by who-knows-what, it renders the princess face unusable on smaller devices like iPhones. If you want to see the clown face in action, Clockinator is available on the app store, and it's completely free with no ads or anything.

   

GeometryReader is a greedy View that expands out to take up all available space. To limit how much space it takes up, you need to limit the frame it's in, either by assigning an explicit frame size or through some other method, such as putting it in a background or overlay on another View.

   

so can i put my path.addArc calls in a view and put the geometryreader in an overlay to get my widths? and the use those widths in my view under the overlay? or will my widths be restricted to the overlay?

   

background and overlay are restricted to the size of the View they are attached to, so the GeometryReader will only expand as far as the View's frame.

See this FiveStars blog post for a nifty readSize modifier to get the size of a View and pass it up the hierarchy.

Hopefully this will help you achieve the effect you are looking for.

1      

Thank you. This did help. I suspected it was the grabby-ness of GeometryReader the whole time but wasn't sure what to do with that information. The FiveStars blog post was exactly what I needed. It's working now.

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.