我在尝试动画并更改闭包内的ui元素的某些属性时遇到问题。当我尝试通过函数动画一些视图时,它执行函数但动画无法完成,但是当我在闭包外执行函数时,它工作正常。这是我的代码,我的问题出在AuthController
底部的委托扩展中,名为facebookAuth
的函数。我几乎挣扎了一天,我找不到错误。
我在动画中设置了一些打印语句,并且用于追踪目的,这些是执行的:
登录成功(这个是在委托函数中
幻灯片(这个是滑动功能)
不完整(这个是在动画关闭中)
AuthController
import UIKit
import AVFoundation
import FBSDKLoginKit
import FBSDKCoreKit
import Firebase
protocol AuthControllerDelegate {
func login(withUser user: User)
func facebookAuth()
func signUp(withUser user: User)
func facebookRegister(withEmail email: String, cellphone: String)
}
class AuthController: UIViewController {
enum AuthView {
case registerView
case loginView
case fbRegisterSecondStepCenter
}
private var player: AVPlayer!
private var playerLayer: AVPlayerLayer!
private var registerViewCenterConstraint: NSLayoutConstraint?
private var loginViewCenterConstraint: NSLayoutConstraint?
private var fbRegisterSecondStepCenterConstraint: NSLayoutConstraint?
private var currentView: AuthView = .loginView
private var facebookUserStore: User?
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
private let purpleBackground: UIView = {
let pb = UIView()
pb.backgroundColor = .darkBackground
pb.alpha = 0.5
return pb
}()
//MARK: AuthViews
private lazy var loginView: LoginView = {
let view = LoginView()
view.delegate = self
return view
}()
private lazy var registerView: RegisterView = {
let view = RegisterView()
// view.delegate = self
view.alpha = 0
return view
}()
private lazy var fbRegisterSecondStep: FBRegisterSecondStep = {
let view = FBRegisterSecondStep()
view.alpha = 0
view.delegate = self
return view
}()
private lazy var bottomBtn: UIButton = {
let btn = UIButton()
let attributedString = NSMutableAttributedString(string: "Not registered? Sign up.", attributes: [.foregroundColor: UIColor.lightText, .font: UIFont.init(name: Fonts.lightFont.rawValue, size: 16)!])
btn.setAttributedTitle(attributedString, for: .normal)
btn.contentHorizontalAlignment = .center
btn.addTarget(self, action: #selector(handleChangeView), for: .touchUpInside)
return btn
}()
let alertController: AlertController = {
let ac = AlertController()
return ac
}()
override func viewDidLoad() {
super.viewDidLoad()
print(UserDefaults.Account.bool(forKey: .isUserLoggedIn))
setVideoBackground()
setupViews()
alertController.transitioningDelegate = alertController
alertController.modalPresentationStyle = .custom
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = false
}
private func setupViews() {
view.addSubview(purpleBackground)
view.addSubview(loginView)
view.addSubview(registerView)
view.addSubview(fbRegisterSecondStep)
view.addSubview(bottomBtn)
_ = purpleBackground.anchor(top: view.topAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, left: view.leftAnchor)
loginViewCenterConstraint = loginView.centerInView().first
_ = loginView.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.6)
registerViewCenterConstraint = registerView.centerInView().first
registerViewCenterConstraint?.constant = 1000
_ = registerView.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.8)
fbRegisterSecondStepCenterConstraint = fbRegisterSecondStep.centerInView().first
fbRegisterSecondStepCenterConstraint?.constant = 1000
_ = fbRegisterSecondStep.anchorWithMultiplier(top: nil, bottom: nil, right: nil, left: nil, height: view.heightAnchor, width: view.widthAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0.8, heightMultiplier: 0.5)
_ = bottomBtn.anchor(top: nil, bottom: view.bottomAnchor, right: view.rightAnchor, left: view.leftAnchor, topConstant: 0, bottomConstant: 20, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 0)
}
private func setVideoBackground() {
let videoPath = Bundle.main.url(forResource: "trim720", withExtension: "mp4")
player = AVPlayer(url: videoPath!)
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspectFill
playerLayer.frame = view.frame
player.actionAtItemEnd = .none
player.play()
view.layer.insertSublayer(playerLayer, at: 0)
NotificationCenter.default.addObserver(self, selector: #selector(handleStop), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
}
private func slide(toView view: AuthView, completion: @escaping (Bool) -> Void = { _ in }) {
guard let registerCenterConstraint = registerViewCenterConstraint, let loginCenterConstraint = loginViewCenterConstraint, let fbRegisterSecondConstraint = fbRegisterSecondStepCenterConstraint else {
fatalError("Error unwrapping auth views constraints.")
}
switch view {
case .loginView:
loginCenterConstraint.constant = 0
registerCenterConstraint.constant = 1000
fbRegisterSecondConstraint.constant = 1000
currentView = .loginView
case .registerView:
loginCenterConstraint.constant = 1000
registerCenterConstraint.constant = 0
fbRegisterSecondConstraint.constant = 1000
currentView = .registerView
case .fbRegisterSecondStepCenter:
loginCenterConstraint.constant = 1000
registerCenterConstraint.constant = 1000
fbRegisterSecondConstraint.constant = 0
currentView = .fbRegisterSecondStepCenter
print("slideeeeeeeeeeee")
}
let isRegisterVisible = registerCenterConstraint.constant == 0
let isLoginVisible = loginCenterConstraint.constant == 0
let isFbRegisterVisible = fbRegisterSecondConstraint.constant == 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.registerView.alpha = isRegisterVisible ? 1 : 0
self.loginView.alpha = isLoginVisible ? 1 : 0
self.fbRegisterSecondStep.alpha = isFbRegisterVisible ? 1 : 0
self.view.layoutIfNeeded()
print("slide")
}) { (state) in
if state {
print("completed")
} else {
print("not completed")
}
completion(state)
}
}
fileprivate func pushHome() {
navigationController?.isNavigationBarHidden = false
navigationController?.setViewControllers([HomeController()], animated: true)
}
// MARK: Handlers
@objc private func handleStop() {
player.seek(to: kCMTimeZero)
}
@objc private func handleChangeView() {
let isLoginVisible = currentView == .loginView
let view: AuthView = isLoginVisible ? .registerView : .loginView
slide(toView: view) { (completed) in
let attributedString = self.bottomBtn.attributedTitle(for: .normal) as! NSMutableAttributedString
let newTitle = isLoginVisible ? "Already an user? Sign In" : "Not registered? Sign up."
attributedString.mutableString.setString(newTitle)
}
}
}
extension AuthController: Loginable, Registable, AuthControllerDelegate {
func login(withUser user: User) {
signIn(withUser: user) { (_) in
self.pushHome()
}
}
func facebookAuth(){
let loginManager = FBSDKLoginManager()
loginManager.logIn(withReadPermissions: ["email", "public_profile"], from: self) { (result, err) in
if err == nil, !(result?.isCancelled)!, let token = result?.token.tokenString {
print("Login successful")
self.loginView.isHidden = true
self.bottomBtn.isHidden = true
self.slide(toView: .registerView)
}
}
}
func facebookRegister(withEmail email: String, cellphone: String) {
guard let user = facebookUserStore else {
fatalError("Error linking accounts")
}
register(withUser: user) { (completed) in
if completed {
self.linkAccount(withEmail: email, cellphone: cellphone, completion: { (completion) in
if completion {
self.pushHome()
}
})
}
}
}
func signUp(withUser user: User) {
register(withUser: user) { (_) in
print("registrado")
UserDefaults.Account.set(true, forKey: .isUserLoggedIn)
self.pushHome()
}
}
}
当单击fbButton时,该函数通过此视图中的委托执行。
LoginView
//
// LoginView.swift
// TaxiApp
//
// Created by Leonardo Dominguez on 10/2/17.
// Copyright © 2017 Leonardo Dominguez. All rights reserved.
//
import UIKit
class LoginView: BaseView {
var delegate: AuthControllerDelegate?
private let emailField: TAField = {
let pf = TAField(placeHolder: "E-mail", keyboardType: .emailAddress)
return pf
}()
private let passwordField: TAField = {
let pf = TAField(placeHolder: "Password")
pf.isSecureTextEntry = true
return pf
}()
private lazy var loginBtn: TAButton = {
let btn = TAButton(title: "Login")
btn.addTarget(self, action: #selector(handleLogin), for: .touchUpInside)
return btn
}()
private let facebookBtn: TAButton = {
let btn = TAButton()
btn.backgroundColor = UIColor(hexString: "#3b5998")
btn.setAttributedTitle(NSAttributedString(string: "Login with Facebook", attributes: [.foregroundColor: UIColor.lightText, .font: UIFont.init(name: Fonts.mediumFont.rawValue, size: 20)!]), for: .normal)
return btn
}()
private let forgotPassword: UIButton = {
let btn = UIButton()
btn.setAttributedTitle(NSAttributedString(string: "Forgot password", attributes: [.foregroundColor: UIColor.placeholderText, .font: UIFont.init(name: Fonts.mediumFont.rawValue, size: 16)!]), for: .normal)
btn.contentHorizontalAlignment = .right
return btn
}()
private let orView: UIView = {
let container = UIView()
let lbl = UILabel()
lbl.text = "or"
lbl.textColor = .lightText
lbl.font = UIFont(name: Fonts.mediumFont.rawValue, size: 20)
let leftLine = UIView()
let rightLine = UIView()
leftLine.backgroundColor = .lightLine
rightLine.backgroundColor = .lightLine
container.addSubview(rightLine)
container.addSubview(lbl)
container.addSubview(leftLine)
rightLine.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
_ = rightLine.anchor(top: nil, bottom: nil, right: container.rightAnchor, left: lbl.rightAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 70, leftConstant: 3, widthConstant: 0, heightConstant: 1.0)
_ = lbl.centerInView()
leftLine.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
_ = leftLine.anchor(top: nil, bottom: nil, right: lbl.leftAnchor, left: container.leftAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 3, leftConstant: 70, widthConstant: 0, heightConstant: 1.0)
return container
}()
override func setupViews() {
setupBtns()
addSubview(emailField)
addSubview(passwordField)
addSubview(forgotPassword)
addSubview(loginBtn)
addSubview(orView)
addSubview(facebookBtn)
_ = emailField.anchor(top: topAnchor, bottom: nil, right: rightAnchor, left: leftAnchor, topConstant: 20, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: Theme.fieldHeight)
_ = passwordField.anchorWithMultiplier(top: emailField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)
_ = forgotPassword.anchor(top: passwordField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, topConstant: 5, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 0)
_ = loginBtn.anchorWithMultiplier(top: passwordField.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)
_ = orView.anchor(top: loginBtn.bottomAnchor, bottom: nil, right: rightAnchor, left: leftAnchor, topConstant: Theme.topPadding / 2, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 10)
_ = facebookBtn.anchorWithMultiplier(top: orView.bottomAnchor, bottom: nil, right: emailField.rightAnchor, left: emailField.leftAnchor, height: emailField.heightAnchor, width: nil, topConstant: Theme.topPadding / 2, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthMultiplier: 0, heightMultiplier: 1)
}
func setupBtns() {
facebookBtn.addTarget(self, action: #selector(handleFacebookLogin), for: .touchUpInside)
}
@objc func handleFacebookLogin() {
delegate?.facebookAuth()
}
@objc func handleLogin() {
if let email = emailField.text, let password = passwordField.text {
let user = User(email: email, password: password)
delegate?.login(withUser: user)
}
}
}
更新
所以经过很多patinete尝试整个应用程序后,我只是注意到该错误属于RouterController
,它是一个UINavigationController子类,其中嵌入了AuthController
。当我更改windows rootviewcontroller以避免RouterController
并直接转到AuthController
时,一切都开始工作了......现在我的疑问是,为什么会发生这种情况?我试图搞清楚,所以我可以修复或将来的情况但我不知道为什么,这是我的代码:
RouterController
import UIKit
class RouterController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// perform(#selector(redirect), with: nil, afterDelay: 0)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
redirect()
}
@objc func redirect() {
if UserDefaults.Account.bool(forKey: .isUserLoggedIn) {
viewControllers = [HomeController()]
} else {
setViewControllers([AuthController()], animated: false)
}
}
}
答案 0 :(得分:0)
尝试在主线程的闭包中执行所有内容,如下所示:
func facebookAuth(){
let loginManager = FBSDKLoginManager()
loginManager.logIn(withReadPermissions: ["email", "public_profile"], from: self) {[weak self] (result, err) in
if err == nil, !(result?.isCancelled)!, let token = result?.token.tokenString {
print("Login successful")
DispatchQueue.main.async {
self?.loginView.isHidden = true
self?.bottomBtn.isHidden = true
self?.slide(toView: .registerView)
}
}
}
}