Sliding one SwiftUI view out from underneath another

后端 未结 2 696
旧巷少年郎
旧巷少年郎 2021-02-09 00:17

I\'m attempting to construct an animation using SwiftUI.

Start: [ A ][ B ][ D ]
End:   [ A ][ B ][    C    ][ D ]

The key elements of the anima

2条回答
  •  無奈伤痛
    2021-02-09 01:07

    Since I originally replied to this question, I have been investigating GeometryReader, View Preferences and Anchor Preferences. I have assembled a detailed explanation that elaborates further. You can read it at: https://swiftui-lab.com/communicating-with-the-view-tree-part-1/

    Once you get the CCCCCCCC view geometry into the textRect variable, the rest is easy. You simply use the .offset(x:) modifier and clipped().

    import SwiftUI
    
    struct RectPreferenceKey: PreferenceKey {
        static var defaultValue = CGRect()
    
        static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
            value = nextValue()
        }
    
        typealias Value = CGRect
    }
    
    struct ContentView : View {
        @State private var textRect = CGRect()
        @State private var slideOut = false
    
        var body: some View {
    
            return VStack {
                HStack(spacing: 0) {
                    Text("AAAAAA")
                        .font(.largeTitle)
                        .background(Color.yellow)
                        .zIndex(4)
    
    
                    Text("BBBB")
                        .font(.largeTitle)
                        .background(Color.red)
                        .zIndex(3)
    
                    Text("I am a very long text")
                        .zIndex(2)
                        .font(.largeTitle)
                        .background(GeometryGetter())
                        .background(Color.green)
                        .offset(x: slideOut ? 0.0 : -textRect.width)
                        .clipped()
                        .onPreferenceChange(RectPreferenceKey.self) { self.textRect = $0 }
    
                    Text("DDDDDDDDDDDDD").font(.largeTitle)
                        .zIndex(1)
                        .background(Color.blue)
                        .offset(x: slideOut ? 0.0 : -textRect.width)
    
                }.offset(x: slideOut ? 0.0 : +textRect.width / 2.0)
    
                Divider()
                Button(action: {
                    withAnimation(.basic(duration: 1.5)) {
                        self.slideOut.toggle()
                    }
                }, label: {
                    Text("Animate Me")
                })
            }
    
        }
    }
    
    struct GeometryGetter: View {
        var body: some View {
            GeometryReader { geometry in
                return Rectangle()
                    .fill(Color.clear)
                    .preference(key: RectPreferenceKey.self, value:geometry.frame(in: .global))
            }
        }
    }
    

提交回复
热议问题