我试图在一个有多行的Text
上添加一个扩展/收缩动画,但是我有一个奇怪的行为。
下面是这个问题的gif。我已经设置了缓慢的动画,以使其清晰。
https://www.dropbox.com/s/sx41g9tfx4hd378/expand-collapse-stack_overflow.gif
我正在对视图的height属性进行动画处理,似乎无论动画周期如何,Text
都会立即转换为一行。下面是一些代码:
struct ContentView: View {
@State var expanded = false
var body: some View {
VStack(spacing: 20) {
HStack {
Button(expanded ? "Colapse" : "Expand") {
withAnimation {
self.expanded.toggle()
}
}
}
VStack(spacing: 10) {
Text(bigText)
Text(bigText)
}
.frame(height: expanded ? .none : 0)
.clipped()
.background(Color.red)
Text("Thist is another text underneath the huge one. ")
.font(.system(.headline))
.foregroundColor(.red)
Spacer()
}
}
}
我已经尝试了很多其他方法,这是目前最接近所需输出的方法,这与在UIKit中为UIStackView
中的标签设置动画效果相同。
有没有办法正确地做到这一点呢?这是一个bug吗?通常情况下,问题来自开发人员,但我注意到,如果我使用DisclosureGroup
,当它展开时,动画可以工作,但当它折叠时,它根本没有动画。所以这实际上可能是多行Text
的一个限制
非常感谢。
发布于 2021-09-27 18:16:33
嗯,问题是我们在nil
和0
之间设置了帧动画,但对于内部文本项,只有边缘值被传输。
要解决这个问题,需要完成两个步骤:
所以这里是一个方法的演示。用Xcode13/ iOS 15编写
注意:在模拟器中激活慢速动画,以获得更好的可见性
let bigText = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
"""
struct ContentView: View {
// we need `true` on construction (not visible) to calculate
// max content height
@State var expanded = true // << required initial true !!
@State private var maxHeight: CGFloat?
var body: some View {
VStack(spacing: 20) {
HStack {
Button(expanded ? "Colapse" : "Expand") {
withAnimation {
self.expanded.toggle()
}
}
}
VStack(spacing: 10) {
Text(bigText)
Text(bigText)
}
.background(GeometryReader { // read content height
Color.clear.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.height)
})
.onPreferenceChange(ViewHeightKey.self) {
if nil == self.maxHeight {
self.maxHeight = $0 // << needed once !!
}
}
.modifier(AnimatingFrameHeight(height: expanded ? maxHeight ?? .infinity : 0))
.clipped()
.background(Color.red)
Text("Thist is another text underneath the huge one. ")
.font(.system(.headline))
.foregroundColor(.red)
Spacer()
}
.onAppear {
// this cases instance redraw on first render
// so initial state will be invisible for user
expanded = false // << set if needed here !!
}
}
}
struct AnimatingFrameHeight: AnimatableModifier {
var height: CGFloat = 0
var animatableData: CGFloat {
get { height }
set { height = newValue }
}
func body(content: Content) -> some View {
content.frame(height: height)
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value + nextValue()
}
}
https://stackoverflow.com/questions/69350410
复制相似问题