Post

Replies

Boosts

Views

Activity

SwiftUI: Sheet Modal, unexpected resize behavior
Hey Everyone, I've been remaking an app using SwiftUI, and I am running into a weird animation bug/hitch using .sheet(isPresented:). I have a GIF illustrating the issue, but can't seem to attach it to this forum post. Let me know if there's anyway to share this. Link to gif detailing issue(self hosted) Regardless, my issue: To describe the issue: I'm using two Detents for the sheet, [.medium, .large]. I have a TextField that's displayed in the sheet, and when opening it, the keyboard moves my content upward (expected, working fine). My issue comes when I programmatically resign the TextField (using .focused($isFocused). The content on the sheet jumps up, beyond the upper bound of the sheet. My hypothesis is that the sheet's content is immediately redrawn, using the medium detent frame, but before the animation has finished going from large to medium. It's possible this is not a SwiftUI bug, but something wrong with my implementation. I'll provide the relevant code below. Any help is greatly appreciated! Onboarding.swift (presents the sheet) @ViewBuilder var content: some View { VStack { headline .foregroundStyle(.white.opacity(0.95)) subHeadline .foregroundStyle(.white) Spacer() messages .foregroundStyle(.white) Spacer() callToAction } .ignoresSafeArea(.keyboard) .sheet(isPresented: $showJoin) { join } } var join: some View { Join() .ignoresSafeArea() .presentationCornerRadius(40) .presentationDragIndicator(.hidden) .presentationBackground { Rectangle() .fill(.ultraThinMaterial) .padding(.bottom, -1000) } .presentationDetents([.medium, .large]) } Join.swift (holds the sheet's content, and displays the heading) struct Join: View { @State private var didSignUp = false var body: some View { VStack { heading Divider() contentView } .animation(.easeInOut, value: didSignUp) .transition(.opacity) .interactiveDismissDisabled(didSignUp) } var heading: some View { VStack(spacing: 8) { Text(didSignUp ? "Verify" : "Start here") .frame(maxWidth : .infinity, alignment: .leading) .font(.largeTitle.bold()) .foregroundColor(.primary) .blendMode(.overlay) Text(didSignUp ? "Enter code" : "Create an account") .frame(maxWidth : .infinity, alignment: .leading) .font(.callout) .foregroundColor(.primary) .blendMode(.overlay) } .padding(.top, 20) .padding(.horizontal) } var contentView: some View { Group { if didSignUp { Verification() .transition(.move(edge: .trailing).combined(with: .opacity)) } else { SignUp(didSignUp: $didSignUp) .transition(.move(edge: .leading).combined(with: .opacity)) } } .padding(.horizontal) } } SignUp.swift (the sheet content) struct SignUp: View { @Binding var didSignUp: Bool @State private var phoneNumber: String = "" @State private var sendingTextMessage = false @FocusState private var isFocused: Bool private let notice = """ By creating an account, you agree to our **[Terms of Service](https://cordia.app/tos)** and **[Privacy Policy](https://cordia.app/privacy)** """ var body: some View { VStack { VStack { phoneNumberLabel phoneNumberInput } .padding() if sendingTextMessage { LoadingIndicator(isVisible: $sendingTextMessage) .padding() } else { continueButton .padding() } Spacer() termsAndConditions .padding(.bottom) } } var phoneNumberLabel: some View { Text("Enter your phone number") .font(.title3) .foregroundColor(.primary) .blendMode(.overlay) .frame(maxWidth: .infinity, alignment: .leading) } var phoneNumberInput: some View { iPhoneNumberField("(***) 867-5309", text: $phoneNumber) .maximumDigits(10) .formatted() .clearsOnEditingBegan(true) .clearButtonMode(.always) .font(.system(size: 25, weight: .semibold)) .padding() .glass(cornerRadius: 10) .focused($isFocused) } var termsAndConditions: some View { Text(addPolicyLinks() ?? AttributedString(notice)) .multilineTextAlignment(.center) .fixedSize(horizontal: false, vertical: true) .font(.body) .blendMode(.overlay) .padding() } var continueButton: some View { Button(action: { guard !sendingTextMessage else { return } sendingTextMessage = true isFocused = false UIImpactFeedbackGenerator(style: .rigid).impactOccurred() Auth.signUp(with: phoneNumber) { user, error in didSignUp = true } }) { Text("Join Cordia") .font(.system(size: 25, weight: .semibold)) .foregroundColor(.primary.opacity(0.8)) .frame(width: 200, height: 60) .tintedGlass( cornerRadius: 20, strokeColor: .cordiaGoldDark, strokeSize: 1.0, tint: .cordiaGold ) } } private func addPolicyLinks() -> AttributedString? { var string = try? AttributedString(markdown: notice) if let range = string?.range(of: "Terms of Service") { string?[range].foregroundColor = .cordiaGold } if let range = string?.range(of: "Privacy Policy") { string?[range].foregroundColor = .cordiaGold } return string } }
4
0
2.3k
Dec ’23