我有一个登录页面,其中视图嵌入ZStack
到我的目标是当我单击ZStack 应该的email
和字段时,它不会被键盘覆盖。我通过在文本字段中设置状态来实现此行为。它在预览设备上工作得非常好,但是当我在模拟器和我的物理设备(iPhone xs 最新操作系统版本)上运行它时,子视图的行为发生变化并且没有正确偏移(参见下图以供参考)。password
offset -300 vertically
onTapGesture
Color("background2")
HStack
login button
文件的完整代码:
import SwiftUI
import Firebase
struct LoginView: View {
@State var email = ""
@State var password = ""
@State var isFocused = false
@State var showAlert = false
@State var alertMessage = "Something went wrong."
@State var isLoading = false
@State var isSuccessful = false
func login() {
self.hideKeyboard()
self.isFocused = false
self.isLoading = true
Auth.auth().signIn(withEmail: email, password: password) { result, error in
self.isLoading = false
if error != nil {
self.alertMessage = error?.localizedDescription ?? ""
self.showAlert = true
} else {
self.isSuccessful = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.email = ""
self.password = ""
self.isSuccessful = false
}
}
}
}
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
var body: some View {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
ZStack(alignment: .top) {
// Gray background
Color("background2")
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.edgesIgnoringSafeArea(.bottom)
// Design card-like view
CoverView()
// Email and Password fields
VStack {
HStack {
Image(systemName: "person.crop.circle.fill")
.foregroundColor(Color(#colorLiteral(red: 0.6549019608, green: 0.7137254902, blue: 0.862745098, alpha: 1)))
.frame(width: 44, height: 44)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.shadow(color: Color.black.opacity(0.15), radius: 5, x: 0, y: 5)
.padding(.leading)
TextField("Your Email".uppercased(), text: $email)
.keyboardType(.emailAddress)
.font(.subheadline)
// .textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.leading)
.frame(height: 44)
.onTapGesture {
self.isFocused = true
}
}
Divider().padding(.leading, 80)
HStack {
Image(systemName: "lock.fill")
.foregroundColor(Color(#colorLiteral(red: 0.6549019608, green: 0.7137254902, blue: 0.862745098, alpha: 1)))
.frame(width: 44, height: 44)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.shadow(color: Color.black.opacity(0.15), radius: 5, x: 0, y: 5)
.padding(.leading)
SecureField("Password".uppercased(), text: $password)
.keyboardType(.default)
.font(.subheadline)
// .textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.leading)
.frame(height: 44)
.onTapGesture {
self.isFocused = true
}
}
}
.frame(height: 136)
.frame(maxWidth: .infinity)
.background(BlurView(style: .systemMaterial))
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.shadow(color: Color.black.opacity(0.15), radius: 20, x: 0, y: 20)
.padding(.horizontal)
.offset(y: 460)
// Forgot password and Login Button view
HStack {
Text("Forgot password?")
.font(.subheadline)
Spacer()
Button(action: {
self.login()
}) {
Text("Log in").foregroundColor(.black)
}
.padding(12)
.padding(.horizontal, 30)
.background(Color(#colorLiteral(red: 0, green: 0.7529411765, blue: 1, alpha: 1)))
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
.shadow(color: Color(#colorLiteral(red: 0, green: 0.7529411765, blue: 1, alpha: 1)).opacity(0.3), radius: 20, x: 0, y: 20)
.alert(isPresented: $showAlert) {
Alert(title: Text("Error"), message: Text(self.alertMessage), dismissButton: .default(Text("OK")))
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.padding()
}
.offset(y: isFocused ? -300 : 0)
.animation(isFocused ? .easeInOut : nil)
.onTapGesture {
self.isFocused = false
self.hideKeyboard()
}
if isLoading {
LoadingView()
}
if isSuccessful {
SuccessView()
}
}
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
// .previewDevice("iPad Air 2")
}
}
struct CoverView: View {
@State var show = false
@State var viewState = CGSize.zero
@State var isDragging = false
var body: some View {
VStack {
GeometryReader { geometry in
Text("Quizzes that fit on your pocket.")
.font(.system(size: geometry.size.width/10, weight: .bold))
.foregroundColor(.white)
}
.frame(maxWidth: 375, maxHeight: 100)
.padding(.horizontal, 16)
.offset(x: viewState.width/15, y: viewState.height/15)
Text("Keep on learning new things!")
.font(.subheadline)
.frame(width: 250)
.offset(x: viewState.width/20, y: viewState.height/20)
Spacer()
}
.multilineTextAlignment(.center)
.padding(.top, 100)
.frame(height: 477)
.frame(maxWidth: .infinity)
.background(
ZStack {
Image(uiImage: #imageLiteral(resourceName: "Blob"))
.offset(x: -150, y: -200)
.rotationEffect(Angle(degrees: show ? 360+90 : 90))
.blendMode(.plusDarker)
// .animation(Animation.linear(duration: 120).repeatForever(autoreverses: false))
.animation(nil)
.onAppear { self.show = true }
Image(uiImage: #imageLiteral(resourceName: "Blob"))
.offset(x: -200, y: -250)
.rotationEffect(Angle(degrees: show ? 360 : 0), anchor: .leading)
.blendMode(.overlay)
// .animation(Animation.linear(duration: 120).repeatForever(autoreverses: false))
.animation(nil)
}
)
.background(
Image(uiImage: #imageLiteral(resourceName: "Card3"))
.offset(x: viewState.width/25, y: viewState.height/25)
, alignment: .bottom
)
.background(Color(#colorLiteral(red: 0.4117647059, green: 0.4705882353, blue: 0.9725490196, alpha: 1)))
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.scaleEffect(isDragging ? 0.9 : 1)
.animation(.timingCurve(0.2, 0.8, 0.2, 1, duration: 0.8))
.rotation3DEffect(Angle(degrees: 5), axis: (x: viewState.width, y: viewState.height, z: 0))
.gesture(
DragGesture().onChanged { value in
self.viewState = value.translation
self.isDragging = true
}
.onEnded { value in
self.viewState = .zero
self.isDragging = false
}
)
}
}