diff --git a/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate b/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate index fd4c7e9..565b2bd 100644 Binary files a/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate and b/wake.xcodeproj/project.xcworkspace/xcuserdata/elliwood.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/wake/Theme.swift b/wake/Theme.swift index a6c3457..30b40cb 100644 --- a/wake/Theme.swift +++ b/wake/Theme.swift @@ -34,6 +34,8 @@ struct Theme { static let textInverse = Color.white // 反色文本 static let textMessage = Color(hex: "7B7B7B") // 注释颜色 static let textMessageMain = Color(hex: "000000") // 注释主要颜色 + static let textWhite = Color(hex: "FFFFFF") // 白色 + static let textWhiteSecondary = Color(hex: "FAFAFA") // 白色次级 // MARK: - 状态色 static let success = Color(hex: "10B981") // 成功色 @@ -119,6 +121,8 @@ extension Color { static var themeTextSecondary: Color { Theme.Colors.textSecondary } static var themeTextMessage: Color { Theme.Colors.textMessage } static var themeTextMessageMain: Color { Theme.Colors.textMessageMain } + static var themeTextWhite: Color { Theme.Colors.textWhite } + static var themeTextWhiteSecondary: Color { Theme.Colors.textWhiteSecondary } } // MARK: - 预览 diff --git a/wake/View/Owner/UserInfo/AvatarPicker.swift b/wake/View/Owner/UserInfo/AvatarPicker.swift index 67e9361..c630fab 100644 --- a/wake/View/Owner/UserInfo/AvatarPicker.swift +++ b/wake/View/Owner/UserInfo/AvatarPicker.swift @@ -6,10 +6,12 @@ public struct AvatarPicker: View { @State private var isUploading = false @Binding var selectedImage: UIImage? @Binding var showUsername: Bool + @Binding var isKeyboardVisible: Bool - public init(selectedImage: Binding, showUsername: Binding) { + public init(selectedImage: Binding, showUsername: Binding, isKeyboardVisible: Binding) { self._selectedImage = selectedImage self._showUsername = showUsername + self._isKeyboardVisible = isKeyboardVisible } public var body: some View { @@ -18,18 +20,22 @@ public struct AvatarPicker: View { Button(action: { showMediaPicker = true }) { - ZStack { + ZStack { if let selectedImage = selectedImage { Image(uiImage: selectedImage) .resizable() .scaledToFill() - .frame(width: 225, height: 225) + .frame(width: isKeyboardVisible ? 125 : 225, + height: isKeyboardVisible ? 125 : 225) .clipShape(RoundedRectangle(cornerRadius: 20)) + .animation(.spring(response: 0.4, dampingFraction: 1), value: isKeyboardVisible) } else { // Default SVG avatar SVGImage(svgName: "Avatar") - .frame(width: 225, height: 225) + .frame(width: isKeyboardVisible ? 125 : 225, + height: isKeyboardVisible ? 125 : 225) .contentShape(Rectangle()) + .animation(.spring(response: 0.4, dampingFraction: 1), value: isKeyboardVisible) } if isUploading { diff --git a/wake/View/Owner/UserInfo/UserInfo.swift b/wake/View/Owner/UserInfo/UserInfo.swift index 888e4bc..b7545ad 100644 --- a/wake/View/Owner/UserInfo/UserInfo.swift +++ b/wake/View/Owner/UserInfo/UserInfo.swift @@ -12,107 +12,198 @@ struct UserInfo: View { @State private var avatarImage: UIImage? @State private var showUsername: Bool = false + // 添加一个状态来跟踪键盘是否显示 + @State private var isKeyboardVisible = false + var body: some View { - VStack(spacing: 0) { - HStack { - ReturnButton { - print("返回") - } - Spacer() - Text("Complete Your Profile") - .font(Typography.font(for: .title2, family: .quicksandBold)) - .foregroundColor(.themeTextMessageMain) - Spacer() - } - .padding() - HStack(spacing: 20) { - Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.") - .font(Typography.font(for: .caption)) - .foregroundColor(.black) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.vertical, 10) - .background( - LinearGradient( - gradient: Gradient(colors: [ - Color(red: 1.0, green: 0.97, blue: 0.87), - .white, - Color(red: 1.0, green: 0.97, blue: 0.84) - ]), - startPoint: .topLeading, - endPoint: .bottomTrailing - ) - ) - } - .padding(10) - Spacer() - VStack(spacing: 20) { - // Title - Text(showUsername ? "Add Your Avatar" : "What‘s Your Name?") - .font(Typography.font(for: .body, family: .quicksandBold)) - .frame(maxWidth: .infinity, alignment: .center) - - // Avatar - ZStack { - AvatarPicker( - selectedImage: $avatarImage, - showUsername: $showUsername - ) - } - .padding(.top, 20) - - if !showUsername { + ZStack { + // 背景色 + Color.themeTextWhiteSecondary + .edgesIgnoringSafeArea(.all) + + VStack(spacing: 0) { + // 固定的顶部导航栏 + HStack { Button(action: { - // Action for second button + dismiss() }) { - Text("Take a Photo") - .font(Typography.font(for: .subtitle, family: .inter)) - .fontWeight(.regular) - .frame(maxWidth: .infinity) - .padding() - .foregroundColor(.black) - .background( - RoundedRectangle(cornerRadius: 16) - .fill(Color.themePrimaryLight) - ) + Image(systemName: "chevron.left") + .font(.system(size: 17, weight: .semibold)) + .foregroundColor(.themeTextMessageMain) + } + .padding(.leading, 16) + + Spacer() + + Text("Complete Your Profile") + .font(Typography.font(for: .title2, family: .quicksandBold)) + .foregroundColor(.themeTextMessageMain) + + Spacer() + + // 添加一个透明的占位视图来平衡布局 + Color.clear + .frame(width: 24, height: 24) + .padding(.trailing, 16) + } + .padding(.vertical, 12) + .background(Color.themeTextWhiteSecondary) + .zIndex(1) // 确保导航栏在最上层 + + // 可滚动的内容区域 + ScrollView { + VStack(spacing: 0) { + // 单行文本(键盘显示时) + if isKeyboardVisible { + HStack(spacing: 20) { + Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.") + .font(Typography.font(for: .caption)) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(1) + .padding(.vertical, 10) + .background( + LinearGradient( + gradient: Gradient(colors: [ + Color(red: 1.0, green: 0.97, blue: 0.87), + .white, + Color(red: 1.0, green: 0.97, blue: 0.84) + ]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + } + .padding(10) + .transition(AnyTransition.opacity.combined(with: .move(edge: .top))) + .animation(.easeInOut(duration: 0.4), value: isKeyboardVisible) + } + // 两行文本(键盘隐藏时) + else { + HStack(spacing: 20) { + Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.") + .font(Typography.font(for: .caption)) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(2) + .padding(.vertical, 10) + .background( + LinearGradient( + gradient: Gradient(colors: [ + Color(red: 1.0, green: 0.97, blue: 0.87), + .white, + Color(red: 1.0, green: 0.97, blue: 0.84) + ]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + } + .padding(10) + .transition(AnyTransition.opacity.combined(with: .move(edge: .top))) + .animation(.easeInOut(duration: 0.25), value: isKeyboardVisible) + } + + if !isKeyboardVisible { Spacer() } + + VStack(spacing: 20) { + // Title + Text(showUsername ? "Add Your Avatar" : "What‘s Your Name?") + .font(Typography.font(for: .body, family: .quicksandBold)) + .frame(maxWidth: .infinity, alignment: .center) + + // Avatar + ZStack { + AvatarPicker( + selectedImage: $avatarImage, + showUsername: $showUsername, + isKeyboardVisible: $isKeyboardVisible + ) + } + .padding(.top, isKeyboardVisible ? 0 : 20) + + if !showUsername { + Button(action: { + // Action for second button + }) { + Text("Take a Photo") + .font(Typography.font(for: .subtitle, family: .inter)) + .fontWeight(.regular) + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(Color.themePrimaryLight) + ) + } + } + + if showUsername { + TextField("Username", text: $userName) + .font(Typography.font(for: .subtitle, family: .inter)) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity) + .padding() + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 16) + .fill(Color.themePrimaryLight) + ) + } + } + .padding() + .background(Color(.white)) + .cornerRadius(20) + .padding(.horizontal) + + if !isKeyboardVisible { Spacer() } + + Button(action: { + showUsername = true + }) { + Text("Continue") + .font(Typography.font(for: .body)) + .fontWeight(.bold) + .frame(maxWidth: .infinity) + .padding(16) + .foregroundColor(.black) + .background( + RoundedRectangle(cornerRadius: 25) + .fill(Color.themePrimary) + ) + } + .padding() + .padding(.bottom, isKeyboardVisible ? 20 : 40) } } - - if showUsername { - TextField("Username", text: $userName) - .font(Typography.font(for: .subtitle, family: .inter)) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .padding() - .foregroundColor(.black) - .background( - RoundedRectangle(cornerRadius: 16) - .fill(Color.themePrimaryLight) - ) - } + .background(Color.themeTextWhiteSecondary) } - .padding() - .background(Color(.white)) - .cornerRadius(20) - Spacer() - Button(action: { - showUsername = true - }) { - Text("Continue") - .font(Typography.font(for: .body)) - .fontWeight(.bold) - .frame(maxWidth: .infinity) - .padding(16) - .foregroundColor(.black) - .background( - RoundedRectangle(cornerRadius: 25) - .fill(Color.themePrimary) - ) + .navigationBarHidden(true) + .navigationBarBackButtonHidden(true) + + // 键盘出现时的半透明覆盖层 + if isKeyboardVisible { + Color.black.opacity(0.001) + .edgesIgnoringSafeArea(.all) + .onTapGesture { + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } } - .padding() } - .padding() - .navigationBarTitleDisplayMode(.inline) - .background(Color(red: 0.98, green: 0.98, blue: 0.98)) // #FAFAFA + .onAppear { + NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in + isKeyboardVisible = true + } + + NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in + isKeyboardVisible = false + } + } + .onDisappear { + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) + } } }