Expected behavior on all tests: The red rectangle will animate it's size from zero to the size of the parent view when the Present button in the top right corner is tapped. When the button is tapped again, the red rectangle will shrink from the size of the parent view to zero.TEST #1 PROPERTY STATE CHANGEActual behavior:Works as expected.Code:struct ContentView: View {
@State private var presentRedBox = false
var body: some View {
NavigationView {
GeometryReader { proxy in
ZStack {
// ------
Rectangle().fill(Color.red)
.frame(
width: self.presentRedBox ? proxy.size.width : 0.0,
height: self.presentRedBox ? proxy.size.height : 0.0
)
// ------
}
}.animation(.default)
.navigationBarItems(trailing: Button("Present") { self.presentRedBox.toggle() })
.navigationBarTitle(Text(""), displayMode: .inline)
}
}
}TEST #2 ANIMATABLE/VIEW MODIFIER USING PROPERTY STATE CHANGEActual behavior:Works as expected.Code:extension AnyTransition {
static func sizeTransition(from: CGSize, to: CGSize) -> AnyTransition {
.modifier(
active: SizeTransition(size: from),
identity: SizeTransition(size: to)
)
}
}
struct SizeTransition: AnimatableModifier {
var size: CGSize
var animatableData: AnimatablePair<cgfloat, cgfloat=""> {
get { AnimatablePair(size.width, size.height) }
set {
size.width = newValue.first
size.height = newValue.second
}
}
func body(content: Content) -> some View {
print(size)
return content.frame(
width: size.width,
height: size.height
)
}
}
struct ContentView: View {
@State private var presentRedBox = false
var body: some View {
NavigationView {
GeometryReader { proxy in
ZStack {
// ------
Rectangle().fill(Color.red)
.modifier(
SizeTransition(
size: self.presentRedBox ? proxy.size : .zero
)
)
// ------
}
}.animation(.default)
.navigationBarItems(trailing: Button("Present") { self.presentRedBox.toggle() })
.navigationBarTitle(Text(""), displayMode: .inline)
}
}
}TEST #3 ANIMATABLE/VIEW MODIFIER WITH TRANSITIONActual behavior:The red box will animate in as expected. However(!) it will NOT animate out but disappear immediately, although the log shows the correct values.Log animate in:(0.0, 0.0)
(1.8118343353271484, 3.3873424530029297)
(7.392631530761719, 13.821006774902344)
(16.9350643157959, 31.66120719909668)
(30.5800838470459, 57.17146110534668)
(48.38059616088867, 90.45067977905273)
(70.25803184509277, 131.35197257995605)
(95.95654678344727, 179.39702224731445)
(124.99998664855957, 233.6956272125244)
(156.67254066467285, 292.90953254699707)
(190.03098106384277, 355.27531242370605)
(223.97296714782715, 418.73206901550293)
(257.33140754699707, 481.0978488922119)
(289.00356674194336, 540.3110160827637)
(318.04700660705566, 594.6096210479736)
(343.7447319030762, 642.6531944274902)
(365.6217727661133, 683.5537490844727)
(383.42189025878906, 716.8322296142578)
(397.06651496887207, 742.3417453765869)
(406.60855293273926, 760.1812076568604)
(412.18856048583984, 770.613395690918)
(414.0, 774.0)Log animate out:(413.61268043518066, 773.2758808135986)
(410.07547760009766, 766.6628494262695)
(402.6749496459961, 752.8270797729492)
(391.2381649017334, 731.4452648162842)
(375.6612854003906, 702.3232727050781)
(355.94628524780273, 665.4647941589355)
(332.24832916259766, 621.1599197387695)
(304.9215717315674, 570.070764541626)
(274.5523223876953, 513.2934722900391)
(241.9665470123291, 452.3722400665283)
(208.19354438781738, 389.231409072876)
(174.37908554077148, 326.0130729675293)
(141.67486381530762, 264.870397567749)
(111.12004852294922, 207.74617767333984)
(83.55758285522461, 156.21635055541992)
(59.59075355529785, 111.40880012512207)
(39.58871841430664, 74.01369094848633)
(23.71967124938965, 44.34547233581543)
(11.994667053222656, 22.42481231689453)
(4.315790176391602, 8.06865119934082)
(0.5136623382568359, 0.9603252410888672)
(0.0, 0.0)Code:extension AnyTransition {
static func sizeTransition(from: CGSize, to: CGSize) -> AnyTransition {
.modifier(
active: SizeTransition(size: from),
identity: SizeTransition(size: to)
)
}
}
struct SizeTransition: AnimatableModifier {
var size: CGSize
var animatableData: AnimatablePair<cgfloat, cgfloat=""> {
get { AnimatablePair(size.width, size.height) }
set {
size.width = newValue.first
size.height = newValue.second
}
}
func body(content: Content) -> some View {
print(size)
return content.frame(
width: size.width,
height: size.height
)
}
}
struct ContentView: View {
@State private var presentRedBox = false
var body: some View {
NavigationView {
GeometryReader { proxy in
ZStack {
// ------
if self.presentRedBox {
Rectangle().fill(Color.red)
.transition(
.modifier(
active: SizeTransition(size: .zero),
identity: SizeTransition(size: proxy.size)
)
)
}
// ------
}
}.animation(.default)
.navigationBarItems(trailing: Button("Present") { self.presentRedBox.toggle() })
.navigationBarTitle(Text(""), displayMode: .inline)
}
}
}TEST #4 ANIMATABLE/VIEW MODIFIER WITH TRANSITION FOR OPACITYExpected behavior:The red rectangle will animate it's opacity from zero (hidden) to one (visible) when the Present button in the top right corner is tapped. When Present is tapped again, the red rectangle will hide from one (visible) to zero (hidden).Actual behavior:Works as expected.Code:extension AnyTransition {
static func sizeTransition(from: CGSize, to: CGSize) -> AnyTransition {
.modifier(
active: SizeTransition(size: from),
identity: SizeTransition(size: to)
)
}
}
struct SizeTransition: AnimatableModifier {
var size: CGSize
var animatableData: AnimatablePair<cgfloat, cgfloat=""> {
get { AnimatablePair(size.width, size.height) }
set {
size.width = newValue.first
size.height = newValue.second
}
}
func body(content: Content) -> some View {
print(size)
return content.opacity(Double(size.width))
}
}
struct ContentView: View {
@State private var presentRedBox = false
var body: some View {
NavigationView {
GeometryReader { proxy in
ZStack {
// ------
if self.presentRedBox {
Rectangle().fill(Color.red)
.transition(
.modifier(
active: SizeTransition(size: .zero),
identity: SizeTransition(size: CGSize(width: 1.0, height: 1.0))
)
)
}
// ------
}
}.animation(.default)
.navigationBarItems(trailing: Button("Present") { self.presentRedBox.toggle() })
.navigationBarTitle(Text(""), displayMode: .inline)
}
}
}