feat: 键盘动效
This commit is contained in:
parent
df82849352
commit
12bcc46f45
Binary file not shown.
@ -34,6 +34,8 @@ struct Theme {
|
|||||||
static let textInverse = Color.white // 反色文本
|
static let textInverse = Color.white // 反色文本
|
||||||
static let textMessage = Color(hex: "7B7B7B") // 注释颜色
|
static let textMessage = Color(hex: "7B7B7B") // 注释颜色
|
||||||
static let textMessageMain = Color(hex: "000000") // 注释主要颜色
|
static let textMessageMain = Color(hex: "000000") // 注释主要颜色
|
||||||
|
static let textWhite = Color(hex: "FFFFFF") // 白色
|
||||||
|
static let textWhiteSecondary = Color(hex: "FAFAFA") // 白色次级
|
||||||
|
|
||||||
// MARK: - 状态色
|
// MARK: - 状态色
|
||||||
static let success = Color(hex: "10B981") // 成功色
|
static let success = Color(hex: "10B981") // 成功色
|
||||||
@ -119,6 +121,8 @@ extension Color {
|
|||||||
static var themeTextSecondary: Color { Theme.Colors.textSecondary }
|
static var themeTextSecondary: Color { Theme.Colors.textSecondary }
|
||||||
static var themeTextMessage: Color { Theme.Colors.textMessage }
|
static var themeTextMessage: Color { Theme.Colors.textMessage }
|
||||||
static var themeTextMessageMain: Color { Theme.Colors.textMessageMain }
|
static var themeTextMessageMain: Color { Theme.Colors.textMessageMain }
|
||||||
|
static var themeTextWhite: Color { Theme.Colors.textWhite }
|
||||||
|
static var themeTextWhiteSecondary: Color { Theme.Colors.textWhiteSecondary }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 预览
|
// MARK: - 预览
|
||||||
|
|||||||
@ -6,10 +6,12 @@ public struct AvatarPicker: View {
|
|||||||
@State private var isUploading = false
|
@State private var isUploading = false
|
||||||
@Binding var selectedImage: UIImage?
|
@Binding var selectedImage: UIImage?
|
||||||
@Binding var showUsername: Bool
|
@Binding var showUsername: Bool
|
||||||
|
@Binding var isKeyboardVisible: Bool
|
||||||
|
|
||||||
public init(selectedImage: Binding<UIImage?>, showUsername: Binding<Bool>) {
|
public init(selectedImage: Binding<UIImage?>, showUsername: Binding<Bool>, isKeyboardVisible: Binding<Bool>) {
|
||||||
self._selectedImage = selectedImage
|
self._selectedImage = selectedImage
|
||||||
self._showUsername = showUsername
|
self._showUsername = showUsername
|
||||||
|
self._isKeyboardVisible = isKeyboardVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
@ -23,13 +25,17 @@ public struct AvatarPicker: View {
|
|||||||
Image(uiImage: selectedImage)
|
Image(uiImage: selectedImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
.frame(width: 225, height: 225)
|
.frame(width: isKeyboardVisible ? 125 : 225,
|
||||||
|
height: isKeyboardVisible ? 125 : 225)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||||
|
.animation(.spring(response: 0.4, dampingFraction: 1), value: isKeyboardVisible)
|
||||||
} else {
|
} else {
|
||||||
// Default SVG avatar
|
// Default SVG avatar
|
||||||
SVGImage(svgName: "Avatar")
|
SVGImage(svgName: "Avatar")
|
||||||
.frame(width: 225, height: 225)
|
.frame(width: isKeyboardVisible ? 125 : 225,
|
||||||
|
height: isKeyboardVisible ? 125 : 225)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.animation(.spring(response: 0.4, dampingFraction: 1), value: isKeyboardVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isUploading {
|
if isUploading {
|
||||||
|
|||||||
@ -12,24 +12,55 @@ struct UserInfo: View {
|
|||||||
@State private var avatarImage: UIImage?
|
@State private var avatarImage: UIImage?
|
||||||
@State private var showUsername: Bool = false
|
@State private var showUsername: Bool = false
|
||||||
|
|
||||||
|
// 添加一个状态来跟踪键盘是否显示
|
||||||
|
@State private var isKeyboardVisible = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
// 背景色
|
||||||
|
Color.themeTextWhiteSecondary
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
|
// 固定的顶部导航栏
|
||||||
HStack {
|
HStack {
|
||||||
ReturnButton {
|
Button(action: {
|
||||||
print("返回")
|
dismiss()
|
||||||
|
}) {
|
||||||
|
Image(systemName: "chevron.left")
|
||||||
|
.font(.system(size: 17, weight: .semibold))
|
||||||
|
.foregroundColor(.themeTextMessageMain)
|
||||||
}
|
}
|
||||||
|
.padding(.leading, 16)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("Complete Your Profile")
|
Text("Complete Your Profile")
|
||||||
.font(Typography.font(for: .title2, family: .quicksandBold))
|
.font(Typography.font(for: .title2, family: .quicksandBold))
|
||||||
.foregroundColor(.themeTextMessageMain)
|
.foregroundColor(.themeTextMessageMain)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
// 添加一个透明的占位视图来平衡布局
|
||||||
|
Color.clear
|
||||||
|
.frame(width: 24, height: 24)
|
||||||
|
.padding(.trailing, 16)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding(.vertical, 12)
|
||||||
|
.background(Color.themeTextWhiteSecondary)
|
||||||
|
.zIndex(1) // 确保导航栏在最上层
|
||||||
|
|
||||||
|
// 可滚动的内容区域
|
||||||
|
ScrollView {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
// 单行文本(键盘显示时)
|
||||||
|
if isKeyboardVisible {
|
||||||
HStack(spacing: 20) {
|
HStack(spacing: 20) {
|
||||||
Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.")
|
Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.")
|
||||||
.font(Typography.font(for: .caption))
|
.font(Typography.font(for: .caption))
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.lineLimit(1)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(
|
.background(
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
@ -44,7 +75,37 @@ struct UserInfo: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding(10)
|
.padding(10)
|
||||||
Spacer()
|
.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) {
|
VStack(spacing: 20) {
|
||||||
// Title
|
// Title
|
||||||
Text(showUsername ? "Add Your Avatar" : "What‘s Your Name?")
|
Text(showUsername ? "Add Your Avatar" : "What‘s Your Name?")
|
||||||
@ -55,10 +116,11 @@ struct UserInfo: View {
|
|||||||
ZStack {
|
ZStack {
|
||||||
AvatarPicker(
|
AvatarPicker(
|
||||||
selectedImage: $avatarImage,
|
selectedImage: $avatarImage,
|
||||||
showUsername: $showUsername
|
showUsername: $showUsername,
|
||||||
|
isKeyboardVisible: $isKeyboardVisible
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding(.top, 20)
|
.padding(.top, isKeyboardVisible ? 0 : 20)
|
||||||
|
|
||||||
if !showUsername {
|
if !showUsername {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
@ -93,7 +155,10 @@ struct UserInfo: View {
|
|||||||
.padding()
|
.padding()
|
||||||
.background(Color(.white))
|
.background(Color(.white))
|
||||||
.cornerRadius(20)
|
.cornerRadius(20)
|
||||||
Spacer()
|
.padding(.horizontal)
|
||||||
|
|
||||||
|
if !isKeyboardVisible { Spacer() }
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
showUsername = true
|
showUsername = true
|
||||||
}) {
|
}) {
|
||||||
@ -109,10 +174,36 @@ struct UserInfo: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
.padding(.bottom, isKeyboardVisible ? 20 : 40)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.background(Color.themeTextWhiteSecondary)
|
||||||
|
}
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.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)
|
||||||
}
|
}
|
||||||
.padding()
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.background(Color(red: 0.98, green: 0.98, blue: 0.98)) // #FAFAFA
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user