我正在尝试使用SwiftUI构建动画。
Start: [ A ][ B ][ D ]
End: [ A ][ B ][ C ][ D ]
Run Code Online (Sandbox Code Playgroud)
动画的关键元素是:
我现在很难用SwiftUI满足所有这些要求,但是过去能够通过自动布局实现类似的效果。
我的第一次尝试是使用HStack带有layoutPriorities 的过渡。这并没有真正接近,因为它会影响动画过程中C的宽度。
我的第二个尝试是保留HStack,但使用带有非对称移动动画的过渡。这确实很接近,但是动画中B和C的移动不会产生C恰好位于B下方的效果。
我最近的尝试是放弃对HStack两个动画视图的依赖,而使用a ZStack代替。通过此设置,我可以结合使用offset和和来使动画完美padding。但是,只有将B和C的帧大小设为已知值,我才能正确解决问题。
是否有人对不要求B和C的帧大小固定的情况有任何想法?
自从我最初回答这个问题以来,我一直在研究GeometryReader,View Preferences和Anchor Preferences。我整理了详细的解释,以作进一步阐述。您可以在以下网址阅读它:https : //swiftui-lab.com/communicating-with-the-view-tree-part-1/
一旦将CCCCCCCC视图几何放入textRect变量中,其余的操作就很容易了。您只需使用.offset(x :)修饰符和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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
很难说清楚你到底想要什么或什么不起作用。如果您展示了您想出的“错误”动画或分享了您的代码,那么帮助您会更容易。
无论如何,这是一个。我认为它有点像你指定的那样,尽管它肯定不完美:
观察结果:
该动画基于 (A) 和 (B) 一起比 (C) 宽的假设。否则,(C) 的部分将在动画开始时出现在 A 的左侧。
同样,动画依赖于视图之间没有间距的事实。否则,当 (C) 比 (B) 宽时,它会出现在 (B) 的左侧。
通过在层次结构中放置不透明底层视图,使其位于 (A)、(B) 和 (D) 下方,但位于 (C) 上方,可以解决这两个问题。但我还没有想清楚这一点。
膨胀的速度似乎HStack比 (C) 滑入的速度快一点,这就是为什么会短暂出现白色部分的原因。我没能消除这个。我尝试将相同的animation(.basic())修饰符添加到HStack、转换、withAnimation调用和VStack,但这没有帮助。
代码:
import SwiftUI
struct ContentView: View {
@State var thirdViewIsVisible: Bool = false
var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack(spacing: 0) {
Text("Lorem ").background(Color.yellow)
.zIndex(1)
Text("ipsum ").background(Color.red)
.zIndex(1)
if thirdViewIsVisible {
Text("dolor sit ").background(Color.green)
.zIndex(0)
.transition(.move(edge: .leading))
}
Text("amet.").background(Color.blue)
.zIndex(1)
}
.border(Color.red, width: 1)
Button(action: { withAnimation { self.thirdViewIsVisible.toggle() } }) {
Text("Animate \(thirdViewIsVisible ? "out" : "in")")
}
}
.padding()
.border(Color.green, width: 1)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1469 次 |
| 最近记录: |