【问题标题】:Animated views resetting position after tapping textfield点击文本字段后动画视图重置位置
【发布时间】:2017-08-02 14:48:15
【问题描述】:

我没有故事板,一切都是程序化的。我有三个 TextField,其中一个是隐藏的(isHidden = true),在登录按钮后面,登录按钮下方是一个注册按钮。如果您点击注册按钮,登录按钮会滑到注册按钮下方,然后使用 layoutSubViews() 显示隐藏的 textField 并将 isHidden 设置为 false。

我的问题是,当点击任何文本字段时,loginButton 会移回其原始位置。我尝试将文本字段委托移动到视图控制器,在 willLayoutSubviews 和 didLayoutSubviews 中调用 setup(),但同样的事情仍然发生。

视图控制器:

class WelcomeScreenViewController: UIViewController {

    private var currentUser: SplitterUser? {
        didSet {
            let nextViewController = MyBillsViewController()
            nextViewController.currentUser = self.currentUser
            present(nextViewController, animated: true)
        }
    }

    // swiftlint:disable line_length
    private let titleLogoLabel = TitleLabelLogo(frame: CGRect.zero, accessID: AccesID.titleLogoLabel)
    private let emailTextField = SplitterTextField(frame: CGRect.zero, accessID: AccesID.emailTextField)
    private let passwordTextField = SplitterTextField(frame: CGRect.zero, accessID: AccesID.passwordTextField)
    private let confirmPasswordTextField = SplitterTextField(frame: CGRect.zero, accessID: AccesID.confirmPasswordTextField)
    private let loginButton = SplitterButton(frame: CGRect.zero, accessID: AccesID.loginButton)
    private let registerButton = SplitterButton(frame: CGRect.zero, accessID: AccesID.registerButton)
    // swiftlint:enable line_length

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    private func setup() {
        view.backgroundColor = Color.mainBackground

        view.addSubview(titleLogoLabel)
        view.addSubview(emailTextField)
        view.addSubview(passwordTextField)
        view.addSubview(confirmPasswordTextField)
        view.addSubview(loginButton)
        view.addSubview(registerButton)

        applyCommonLayoutFeaturesToAllViews()
        placeTitleLogoLabel()
        placeEmailTextField()
        placePasswordTextField()
        placePasswordConfirmationTextField()
        placeLoginButton()
        placeRegisterButton()
        setupKeyboard()
    }

    private func applyCommonLayoutFeaturesToAllViews() {
        view.subviews.forEach { subview in
            subview.pinToSuperview(edges: [.left, .right])
            subview.translatesAutoresizingMaskIntoConstraints = false
        }
    }

    private func placeTitleLogoLabel() {
        let titleLogoLabelY = view.frame.height/4.5
        titleLogoLabel.pinTop(to: view, constant: titleLogoLabelY)
        titleLogoLabel.addHeightConstraint(with: Layout.titleLogoTextHeight)
    }

    private func placeEmailTextField() {
        emailTextField.centerYToSuperview()
        emailTextField.addHeightConstraint(with: Layout.textFieldHeight)
    }

    private func placePasswordTextField() {
        passwordTextField.pinTop(to: emailTextField,
                                 constant: Layout.textFieldHeight + Layout.spacer,
                                 priority: .required,
                                 relatedBy: .equal)
        passwordTextField.addHeightConstraint(with: Layout.textFieldHeight)
    }

    private func placePasswordConfirmationTextField() {
        confirmPasswordTextField.pinTop(to: passwordTextField,
                                        constant: Layout.textFieldHeight + Layout.spacer,
                                        priority: .required,
                                        relatedBy: .equal)
        confirmPasswordTextField.addHeightConstraint(with: Layout.textFieldHeight)
        confirmPasswordTextField.isHidden = true
    }

    private func placeLoginButton() {
        loginButton.pinTop(to: passwordTextField,
                           constant: Layout.textFieldHeight + Layout.spacer,
                           priority: .required,
                           relatedBy: .equal)
        loginButton.addHeightConstraint(with: Layout.buttonHeight)
        loginButton.addTarget(self, action: #selector(loginButtonTapped), for: .touchUpInside)
    }

    private func placeRegisterButton() {
        registerButton.pinTop(to: loginButton,
                              constant: Layout.buttonHeight + Layout.spacer,
                              priority: .required,
                              relatedBy: .equal)
        registerButton.addHeightConstraint(with: Layout.buttonHeight)
        registerButton.addTarget(self, action: #selector(registerButtonTapped), for: .touchUpInside)
    }

    @objc private func registerButtonTapped() {
        if confirmPasswordTextField.isHidden {
            animateLoginButton()
        } else {
            registerNewUser()
        }
    }

    @objc private func loginButtonTapped() {
        if !confirmPasswordTextField.isHidden {
            animateLoginButton()
            self.view.layoutSubviews()
        } else {
            //segue to next vc
        }
    }

    private func animateLoginButton() {
        if confirmPasswordTextField.isHidden {
            moveLoginButtonDown()
        } else {
            moveLoginButtonUp()
        }
    }

    private func moveLoginButtonDown() {
        //Move loginButton down revealing confirmationPasswordTextView behind it
        UIView.animate(withDuration: 0.3, animations: {
            self.loginButton.frame.origin.y += Layout.loginButtonYMovement
            self.confirmPasswordTextField.isHidden = false
        })
    }

    private func moveLoginButtonUp() {
        //Move the loginButton up, when it has finished moving hide the confirmationPasswordTextView
        UIView.animate(withDuration: 0.3, animations: {
            self.loginButton.frame.origin.y -= Layout.loginButtonYMovement
        }, completion: { _ in
            self.confirmPasswordTextField.isHidden = true
        })
    }
}

extension UIViewController {
    func setupKeyboard() {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillShow(sender:)),
                                               name: NSNotification.Name.UIKeyboardWillShow,
                                               object: nil)
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillHide(sender:)),
                                               name: NSNotification.Name.UIKeyboardWillHide,
                                               object: nil)
    }

    @objc private func keyboardWillShow(sender: NSNotification) {
        self.view.frame.origin.y = Layout.welcomeScreenKeyboardMovement
    }

    @objc private func keyboardWillHide(sender: NSNotification) {
        self.view.frame.origin.y = 0
    }
}

文本字段:

class SplitterTextField: UITextField, UITextFieldDelegate {

    var accessID: String!

    required init(frame: CGRect, accessID: String) {
        super.init(frame: frame)
        self.accessID = accessID
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    private func setup() {
        delegate = self
        backgroundColor = Color.textFieldBackground
        accessibilityIdentifier = accessID
        textAlignment = .center
        returnKeyType = .done
        placeholder = NSLocalizedString("\(accessID!)PlaceHolder", comment: "")
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        resignFirstResponder()
        return true
    }
}

我不知道还有什么可以尝试的。任何想法都会很棒。谢谢

【问题讨论】:

  • 当按下登录按钮时,位置正在重置,然后动画你是什么意思?
  • 没有按登录按钮和注册按钮,但当我在登录按钮移动后点击文本字段时,它会重置回起点
  • 除了 textFieldShouldReturn 之外,您的代码中是否有任何文本字段的 edlegate 函数?
  • 不,这是唯一的功能
  • 你在layoutSubviews中有位置设置吗?

标签: ios swift xcode


【解决方案1】:

添加一个您像往常一样键入WelcomeScreenViewController 的XIB 文件(因此没有故事板)。以图形方式创建自动布局约束(这更容易)。

在您的视图控制器代码中有一些这样的约束作为出口,然后您可以对其进行动画处理(根据需要与一些子视图的 alpha 一起)。

我知道这是一个完全不同的解决方案,但我认为你把事情弄得太复杂了。 UIViewController/XIB 对仍然是构建 UI 的一种非常好且简单的方法。

【讨论】:

  • 任务的重点(我已经为自己设定)是不要使用它们,因为我工作的公司不使用任何图形界面。不过谢谢
  • 我明白了。他们为什么不呢?
  • 几个原因,我记得的一个原因是,当多个人在一个项目上工作时,有故事板等会使 github 变得复杂,并且由于您必须通过 IB 搜索而使解决问题变得更加困难。我认为
  • 这确实是不使用 Storyboard 的一个很好的理由。由于这个原因和其他原因,我讨厌 Storyboard。但是他们为什么不为每个屏幕使用代码/XIB 对并自定义UIView?当您与多人在一起时,这一切都很好。
  • 我不确定,因为我没有问。当我这样做时,我会告诉你,我可能是错的,他们确实这样做了,但我认为他们没有。
【解决方案2】:

您已经对视图设置了约束以进行布局。自动布局使用约束来计算视图的框架。那你直接修改loginButton的框架:

self.loginButton.frame.origin.y += Layout.loginButtonYMovement

下次自动布局运行时,它会根据约束重置loginButton的框架。

要移动loginButton,您需要修改设置其框架的约束。因此,例如,您应该保存(在实例变量中)您在placeLoginButton 中创建的顶部约束。然后在moveLoginButtonDown中可以修改保存的约束常量,在动画块中调用self.view.layoutSubviews()。

【讨论】:

  • 我不太明白如何实现你所说的,你介意给我一点帮助吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2016-04-08
  • 1970-01-01
相关资源
最近更新 更多