You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI iOS注册登录页:邮箱验证跳转新视图及代码优化求助

代码优化意见 & 跳转问题解决

一、代码优化点

  • 命名规范修正:Swift变量遵循小驼峰命名,把Error改为isEmailInvalid,ValidationButton直接用isEmailValid判断(省去冗余状态),提升代码可读性。
  • 实时邮箱验证:当前仅在编辑结束时验证,改为监听输入实时响应,用户输入过程中就能得到反馈:
    TextField("Email", text: $email)
        .onChange(of: email) { _ in
            isEmailInvalid = !isEmailValid
        }
    
  • 修复第三方按钮图标错误:Google、Facebook按钮误用了apple.logo,需替换为对应图标(系统无内置的话要导入自定义资源)。
  • 提取重复视图:把三个第三方登录按钮封装成自定义SocialLoginButton,减少代码冗余:
    struct SocialLoginButton: View {
        let iconName: String
        let action: () -> Void
        
        var body: some View {
            Button(action: action) {
                ZStack {
                    RoundedRectangle(cornerRadius: 6)
                        .fill(Color.systemGray5)
                    Image(systemName: iconName)
                        .font(.system(size: 19))
                        .foregroundColor(.primary)
                }
            }
        }
    }
    
    使用时直接调用:SocialLoginButton(iconName: "apple.logo", action: { print("Apple tapped") })
  • 语义化颜色使用:把Color(.systemGray5)改为Color.systemGray5,贴合SwiftUI写法规范。

二、邮箱验证后跳转实现

iOS 16+ 方案(推荐)

用.navigationDestination实现跳转,步骤如下:

  1. 添加导航状态变量:
    @State private var shouldNavigateToNextScreen = false
    
  2. 在NavigationView的根VStack末尾添加导航目标:
    .navigationDestination(isPresented: $shouldNavigateToNextScreen) {
        // 替换成你已创建的目标视图,比如PasswordSetupView()
        Text("下一步:设置密码")
    }
    
  3. 修改验证按钮的action:
    if isEmailValid {
        Button(action: {
            shouldNavigateToNextScreen = true
        }) {
            Image(systemName: "arrow.forward.square.fill")
                .font(.system(size: 35))
        }
        .padding(.leading, 8)
    }
    

iOS 15及以下方案

用NavigationLink结合isActive绑定:

  1. 添加导航状态变量:
    @State private var shouldNavigateToNextScreen = false
    
  2. 在NavigationView的VStack中添加隐藏的NavigationLink:
    NavigationLink(
        destination: YourTargetView(), // 替换为你的目标视图
        isActive: $shouldNavigateToNextScreen
    ) {
        EmptyView()
    }
    .hidden()
    
  3. 同样在验证按钮的action中设置shouldNavigateToNextScreen = true。

优化后的完整代码示例

import SwiftUI

struct Registration: View {
    // MARK: - Properties
    @State private var email = ""
    @State private var isEmailInvalid = false
    @State private var shouldNavigateToNextScreen = false
    
    // Check email
    var isEmailValid: Bool {
        let emailRegex = #"^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"#
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: email)
    }
    
    // MARK: - Body
    var body: some View {
        NavigationView {
            VStack(alignment: .leading, spacing: 40) {
                VStack(spacing: 18) {
                    VStack(alignment: .leading, spacing: 5) {
                        Text("Welcome!")
                            .font(.title)
                            .fontWeight(.bold)
                        Text("Enter your e-mail in order to log in or create an account")
                            .multilineTextAlignment(.leading)
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                    
                    HStack(spacing: 16) {
                        Image(systemName: "envelope.fill")
                            .imageScale(.large)
                            .foregroundColor(.primary)
                        
                        TextField("Email", text: $email)
                            .font(.system(size: 20))
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .foregroundColor(.primary)
                            .onChange(of: email) { _ in
                                isEmailInvalid = !isEmailValid
                            }
                        
                        if isEmailValid {
                            Button(action: {
                                shouldNavigateToNextScreen = true
                            }) {
                                Image(systemName: "arrow.forward.square.fill")
                                    .font(.system(size: 35))
                            }
                            .padding(.leading, 8)
                        }
                    }
                    .padding(.horizontal, 16)
                    .frame(minHeight: 55)
                    .overlay(
                        RoundedRectangle(cornerRadius: 6)
                            .stroke(isEmailInvalid ? .red : .primary)
                    )
                    
                    if isEmailInvalid {
                        Text("Please enter a valid email address")
                            .foregroundColor(.red)
                            .padding(.leading, 16)
                            .frame(maxWidth: .infinity, alignment: .leading)
                    }
                }
                .foregroundColor(.primary)
                
                HStack(spacing: 10) {
                    Rectangle()
                        .fill(Color.separator)
                        .frame(height: 1)
                    Text("or continue with")
                        .fixedSize(horizontal: true, vertical: true)
                        .frame(maxWidth: .infinity)
                    Rectangle()
                        .fill(Color.separator)
                        .frame(height: 1)
                }
                
                HStack(alignment: .top, spacing: 12) {
                    SocialLoginButton(iconName: "apple.logo") {
                        print("Tap on Apple button")
                    }
                    // 注意:Google和Facebook需要替换为正确的图标
                    SocialLoginButton(iconName: "google") {
                        print("Tap on Google button")
                    }
                    SocialLoginButton(iconName: "facebook") {
                        print("Tap on Facebook button")
                    }
                }
                .frame(maxHeight: 50)
                
            }
            .padding(.horizontal, 16)
            .background(Color.systemBackground)
            .navigationBarHidden(true)
            .navigationDestination(isPresented: $shouldNavigateToNextScreen) {
                // 替换成你的目标视图
                Text("Next Registration Step")
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct SocialLoginButton: View {
    let iconName: String
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            ZStack {
                RoundedRectangle(cornerRadius: 6)
                    .fill(Color.systemGray5)
                Image(systemName: iconName)
                    .font(.system(size: 19))
                    .foregroundColor(.primary)
            }
        }
    }
}

struct RegistrationView_Previews: PreviewProvider {
    static var previews: some View {
        Registration()
    }
}

内容的提问来源于stack exchange,提问作者jules

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 03:12:05