Post

Replies

Boosts

Views

Activity

Reply to Has the behavior of asymmetric transitions changed in SwiftUI 4 / iOS 16?
So I took a closer look and it turns out there are TWO issues. And the two issues both happen on iOS 15 and coincidentally they can result in a behaviour that looks correct (you can think of it as double negative resulting in positive). On iOS 16, However, one of the issues is fixed. Therefore, we start to actually notice the faulty behaviour. Use Xcode 14.0: Issuing one (iOS 15 only): .move/.offset/.slide/.scale/.opacity transition is broken when several views, within a switch or if-else statements, have different transitions. They will effect each other. It appears the transition on the insertion view will replace the same transition on the removal view. There're two factors to this: Two or more views in a switch or if-else statement, forming as a group. If you have separate conditions such as two if statements, then this issue won't happen. In OP's example, the old/new Texts (differentiated by the .id modifier) are considered as a group. The participating views have the same type of transition for the corresponding action (inserting or removal). In OP's example, both the old and the new Texts have .move for inserting and .move for removal. It doesn't matter what edge it is, only the type of transition matters. (similarly, .offset(x: 100) and .offset(x: -10) are the same type) Issue Two (Both iOS 15 & iOS 16): change .transition dynamically won't be applied to removing views immediately. Only applied in the next cycle. It makes sense in that transitions are calculated when the view is rendered. It's already there for the existing view so won't be able to change immediately. For insertion view however, the transition is based on the new value so it's applied immediately. To be fair, this one is less of an issue. The behaviour is actually reasonable but not that intuitive. Now, why does OP's example work on iOS 15? Let's say we have Text 1 and Text 2. And we swipe forward, so that pageDirection is set to .forward. What happens? According to Issue Two, when Text 1 is rendered, pageDirection has a default value .forward. At that moment, the insertion transition is .move(.trailing) and the removal transition is .move(.leading). Now, Text 2 is required for insertion. And SwiftUI is going to render it, it will use the current pageDirection, which again is set to .forward. Its insertion transition is .move(.trailing) again and removal .move(.leading). According to Issue One, the inserting view's transition will override the removing view's transition. In this case, they're the same so Text 1 is animating away to the leading edge while Text 2 is animating in from the trailing edge. Now, let's swipe back, so the pageDirection is set to .reverse. What happens? According to Issuing Two, Text 2 will keep using the existing transition. So it will still have insertion transition to be .move(.trailing) and removal .move(.leading). Text 1, on the other hand, is being rendered with pageDirection already set to .reverse. So it will have insertion transition to be .move(.leading) and removal .move(.trailing). According to Issuing One, Text 2 will instead use Text 1's removal transition, .move(.trailing) and you see it animating away to the trailing edge and Text 1 animating in from the leading edge. Perfect! Both behaviours look exactly like what we wanted. However, Issue One is fixed in iOS 16. If we redo the above operation. What happens? First, we swipe forward, pageDirection is set to .forward. Same as iOS 15. Same as iOS 15. Because the transitions between the two views are the same, even without issue one, we still see the same behaviour as iOS 15. But, if we swipe back, pageDirection is set to .reverse. Same as iOS 15 Same as iOS 15 Now, without issue one, we'd respect the transition set in the above two steps. Text 2 will animate away to the leading edge and Text 1 will animate in from the leading edge too! That is exactly the behaviour OP has observed. Using a delay like @CoorielRaw mentioned is a way to fix this on iOS 16. Another option is to create a custom transition like this (very raw, needs a lot of polish): extension AnyTransition {     static func myMove(forward: Binding<Bool>) -> AnyTransition {         return .asymmetric(             insertion: .modifier(                 active: MyMoveModifier(width: 100, forward: forward),                 identity: MyMoveModifier(width: 0, forward: .constant(true))             ),             removal: .modifier(                 active: MyMoveModifier(width: -100, forward: forward),                 identity: MyMoveModifier(width: 0, forward: .constant(true))             )         )     } } struct MyMoveModifier: ViewModifier {     let width: CGFloat     @Binding var forward: Bool          func body(content: Content) -> some View {         content             .offset(x: (forward ? 1 : -1) * width)     } } I'm planning on writing a blog post about this to better share the problems and solutions.
Oct ’22
Reply to About code signing strategy - what happens when we archive a project without code signing, and export it with profile later?
@Anttree Thanks for sharing this. With the new Cloud Signing introduced in Xcode 13, we also want to try this strategy out. To correctly deploy the ipa(exported) file, the archived one should be signed using codesign command Can you elaborate a bit more on this comment? Is there any special entitlement you're using that has been missed if you skip this step? My experiment shows that simply do empty-signing-archive -> export will work. No need to add the code sign step between. The final IPA will have the correct provisioning profile that has all entitlements we use. Maybe because we use just a few entitlements?
Sep ’22