Wrap frame after rotation3DEffect modifier

23 Views Asked by At

I have a view that is two halves of an Image, which I'm attempting to make a folding accordion style animation. As the viewed angle increases towards 90 degrees, the view should be increasingly closer to a height of 0.

struct HeroModuleView: View {
    @Binding var viewedAngle: Double
    
    @State private var offset = 0.0
    @State private var imageFrame: CGRect?
    
    var body: some View {
        ZStack {
            if let image = UIImage(named: "mountain-hero"),
               let topHalf = image.topHalf,
               let bottomHalf = image.bottomHalf {
                
                VStack(spacing: 0) {
                    Image(uiImage: topHalf)
                        .resizable()
                        .scaledToFill()
                        .rotation3DEffect(.degrees(-viewedAngle), axis: (x: 1.0, y: 0.0, z: 0.0), anchor: .top)
                        .offset(y: offset)
                        .clipped()
                        .getFrame(frame: $imageFrame)

                    Image(uiImage: bottomHalf)
                        .resizable()
                        .scaledToFill()
                        .rotation3DEffect(.degrees(viewedAngle), axis: (x: 1.0, y: 0.0, z: 0.0), anchor: .bottom)
                        .offset(y: -offset)
                        .clipped()
                }
                .brightness(-(viewedAngle / 90) * 0.2)
            }
        }
        .frame(maxHeight: 200)
        .onReceive(Just(viewedAngle)) { angle in
            self.offset = (angle / 90) * (imageFrame?.size.height ?? 0)
        }
    }
}

enter image description here

As you can see form the image, the frame, when the image is rotated in 3D space, begins to move towards the anchor point. I have tried adjusting things based on a .center anchor, however the offset doesn't do anything I expect it to and frankly I can't work out the math behind it. I attempted to use some sin calculations but those proved unfruitful. I need the frame of the ZStack to clip the height of both of these views after their effect has been applied, there should be no space above or below them.

0

There are 0 best solutions below