UIView is not visible when inside subview - ios

Inside my project I have Custom-DropDownView. The problem is the actual DropView is not appearing when the DropDownButton is being pressed if the DropDownButton is inside a Subview.
My structure: ViewController -> UIView -> UIStackView -> arrangedSubview ->DropdownButton
If adding the DropDownButton inside the ViewController it works just fine. However if I add it inside the StackView (where I actually need it to be) it won't show the dropView that should appear when the user taps the DropDownButton.
DropDownButton:
class DropDownBtn: UIButton, DropDownProtocol {
let label: UILabel = {
let v = UILabel()
v.font = UIFont(name: "AvenirNext-Regular", size: 15)
v.textColor = .white
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let listImage: UIImageView = {
let v = UIImageView()
v.backgroundColor = .clear
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
func dropDownPressed(string: String, image: UIImage) {
self.setTitle("", for: .normal)
self.label.text = string
self.listImage.image = image
self.dismissDropDown()
}
var dropView = DropDownView()
var height = NSLayoutConstraint()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.layer.borderColor = UIColor.white.cgColor
self.layer.borderWidth = 1.0
self.layer.cornerRadius = 3
// add image
self.addSubview(listImage)
self.listImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
self.listImage.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
self.listImage.widthAnchor.constraint(equalToConstant: 22).isActive = true
self.listImage.heightAnchor.constraint(equalToConstant: 22).isActive = true
// add label
self.addSubview(label)
self.label.leadingAnchor.constraint(equalTo: self.listImage.leadingAnchor, constant: 32).isActive = true
self.label.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
dropView = DropDownView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
dropView.delegate = self
dropView.layer.borderColor = UIColor.white.cgColor
dropView.layer.borderWidth = 1.0
dropView.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
self.superview?.addSubview(dropView)
self.superview?.bringSubviewToFront(dropView)
dropView.bottomAnchor.constraint(equalTo: self.topAnchor).isActive = true
dropView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dropView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
height = dropView.heightAnchor.constraint(equalToConstant: 0)
}
override func removeFromSuperview() {
dropView.bottomAnchor.constraint(equalTo: self.topAnchor).isActive = false
dropView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = false
dropView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = false
}
var isOpen = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false {
isOpen = true
NSLayoutConstraint.deactivate([self.height])
if self.dropView.tableView.contentSize.height > 150 {
self.height.constant = 150
} else {
self.height.constant = self.dropView.tableView.contentSize.height
}
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropView.layoutIfNeeded()
self.dropView.center.y -= self.dropView.frame.height / 2
}, completion: nil)
} else {
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropView.center.y += self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
}, completion: nil)
}
}
func dismissDropDown() {
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseIn, animations: {
self.dropView.center.y += self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
}, completion: nil)
}
Usage at the moment:
Inside UIView:
let dropDownButton: DropDownBtn = {
let v = DropDownBtn()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
and I add it like this (+ using autolayout, the button is displayed perfectly fine and not behind any other view):
theStackView.addArrangedSubview(self.itemView)
itemView.addSubview(dropDownButton)
I tried calling self.view.bringSubViewToFront(self.view.theUIView.dropDownButton.dropView) but that didn't do anything. actual DropDownButton seems alright. I checked it in the View-Hierarchy and I also tested that touchesBegan is actually called and it is.
So I guess the issue is how i constrain the dropView but I am completely stuck here. If anyone can help me out here I am very grateful!
If anything is unclear or you need more code, just let me know!
Update:
The reason the tableView was not visible is because I forgot to call reloadData. However that does not fix the main problem !
The tableView is not clickable when adding it inside the arrangedSubview. Only if I add it to the UIView directly it becomes clickable. In both times the view-hierarchy looks the same.. It is always at the front.
If you want to have a look yourself just let me know and I give you the link to the project.

Related

Why does my UITapGestureRecognizer does not get called when animating the UIView?

I made a toast view with a UIImageView in it, what I want to do is everytime the user taps the image view, the toast dismisses itself. Naturally I configured a UITapGestureRecognizer to my image view, but the selector function is not getting called. Here's what I did:
class ToastView: UIView {
private var icon: UIImageView!
init() {
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
override func layoutSubviews() {
super.layoutSubviews()
setupConstraints()
}
private func setupViews() {
translatesAutoresizingMaskIntoConstraints = false
layer.cornerRadius = 8
isUserInteractionEnabled = true
icon = UIImageView()
icon.translatesAutoresizingMaskIntoConstraints = false
icon.image = UIImage(named: "someImage")
icon.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
icon.addGestureRecognizer(tapGesture)
addSubview(icon)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
topAnchor.constraint(equalTo: superview!.topAnchor, constant: 55),
leadingAnchor.constraint(equalTo: superview!.leadingAnchor, constant: 16),
trailingAnchor.constraint(equalTo: superview!.trailingAnchor, constant: -16),
icon.heightAnchor.constraint(equalToConstant: 16),
icon.widthAnchor.constraint(equalToConstant: 16),
icon.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
icon.centerYAnchor.constraint(equalTo: centerYAnchor),
])
}
#objc private func iconHandler(_ sender: UITapGestureRecognizer) {
// This function is not called
print("handle icon")
}
}
After some research, I tried to give the ToastView a gesture recognizer instead of the image view. So I did give the tap gesture recognizer when showing the toast in my custom UIViewController class like this:
class CustomViewController: UIViewController {
private var isShowingToast: Bool = false
private lazy var toast: ToastView = {
let toast = ToastView()
toast.isUserInteractionEnabled = true
toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
return toast
}()
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
})
}
}
#objc private func dismissToast() {
// This functions does not get called as well
print("dismiss")
}
}
Unfortunately the dismiss function does not print to the console. Is there anyway to resolve this?
Looks like this occurs because of your animation. View is all the time in animation status and block tap gesture. U can try call it with delay instead of adding delay for your animation.
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
print("Completion")
})
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
}
}
}
This way view going to animate status after 5 sec not with 5 sec delay.
This is how your controller look like:
class CustomViewController: UIViewController {
private var isShowingToast: Bool = false
lazy var toast: ToastView = {
let toast = ToastView()
toast.isUserInteractionEnabled = true
toast.backgroundColor = .red
toast.translatesAutoresizingMaskIntoConstraints = false
toast.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissToast)))
return toast
}()
override func viewDidLoad() {
super.viewDidLoad()
// Add Toast constraints
view.addSubview(toast)
toast.heightAnchor.constraint(equalToConstant: 200).isActive = true
toast.widthAnchor.constraint(equalTo: toast.heightAnchor).isActive = true
toast.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
toast.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
func showToastWithMessage() {
if !isShowingToast {
view.addSubview(toast)
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 1
self?.toast.frame.origin.y += 10
self?.isShowingToast = true
}, completion: { _ in
UIView.animate(withDuration: 0.5, delay: 5.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: { [weak self] in
self?.toast.alpha = 0
self?.toast.frame.origin.y -= 10
}, completion: { [weak self] _ in
self?.isShowingToast = false
self?.toast.removeFromSuperview()
})
})
}
}
#objc private func dismissToast() {
// This functions does not get called as well
print("dismiss")
}
}
And this is your class:
class ToastView: UIView {
private var icon = UIImageView()
init() {
super.init(frame: .zero)
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
override func layoutSubviews() {
super.layoutSubviews()
setupConstraints()
}
private func setupViews() {
translatesAutoresizingMaskIntoConstraints = false
layer.cornerRadius = 8
isUserInteractionEnabled = true
icon.translatesAutoresizingMaskIntoConstraints = false
icon.image = UIImage(named: "profilo")?.withRenderingMode(.alwaysOriginal) //put your image here
icon.isUserInteractionEnabled = true
icon.layer.cornerRadius = 8
icon.layer.masksToBounds = true //set image masked round corner
icon.clipsToBounds = true
icon.contentMode = .scaleAspectFill //set image content mode
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(iconHandler))
icon.addGestureRecognizer(tapGesture)
}
private func setupConstraints() {
// Setup the constraints for the subviews
addSubview(icon)
icon.topAnchor.constraint(equalTo: topAnchor).isActive = true
icon.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
icon.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
icon.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
#objc private func iconHandler(_ sender: UITapGestureRecognizer) {
// This function is not called
print("handle icon")
}
}
this is the result:

Trouble With UIViewAnimation

I'm getting in trouble on UIView Animation. When I click into one of UITextFields basically everything works fine until I select another UITextField after being selected the other one, the fields move up and down then return to the same place after I select the other UITextField.
What am I doing wrong? What I expected is to move the whole UIStackView containing my fields into up to avoid the keyboard to cover it all. Also, to keep the animation static when I click into the other UITextField, just returning to the default position when the keyboard got dismissed.
class LoginViewController: UIViewController {
var coordinator: MainCoordinator?
override func viewDidLoad() {
super.viewDidLoad()
viewTapped()
setupScreen()
setupViews()
setConstraints()
}
private func setupScreen() {
self.view.backgroundColor = .systemPink
}
private func setConstraints() {
self.textFieldLogin.heightAnchor.constraint(equalToConstant: 50).isActive = true
self.textFieldLogin.widthAnchor.constraint(equalToConstant: 190).isActive = true
//
self.textFieldSenha.heightAnchor.constraint(equalToConstant: 50).isActive = true
self.textFieldSenha.widthAnchor.constraint(equalToConstant: 190).isActive = true
//
self.loginButton.widthAnchor.constraint(equalToConstant: 145).isActive = true
self.loginButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
//
self.stackView.heightAnchor.constraint(equalToConstant: 200).isActive = true
self.stackView.widthAnchor.constraint(equalToConstant: 200).isActive = true
self.stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
self.stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
private func setupViews() {
self.view.addSubview(self.stackView)
self.viewTapped()
}
private lazy var textFieldLogin: UITextField = {
let textFieldLogin = UITextField()
textFieldLogin.tag = 1
textFieldLogin.translatesAutoresizingMaskIntoConstraints = false
textFieldLogin.layer.cornerRadius = 3.7
textFieldLogin.textAlignment = .center
textFieldLogin.placeholder = "Usuário"
textFieldLogin.backgroundColor = .white
textFieldLogin.delegate = self
return textFieldLogin
}()
private lazy var textFieldSenha: UITextField = {
let textFieldSenha = UITextField()
textFieldSenha.tag = 2
textFieldSenha.translatesAutoresizingMaskIntoConstraints = false
textFieldSenha.layer.cornerRadius = 3.7
textFieldSenha.textAlignment = .center
textFieldSenha.placeholder = "Senha"
textFieldSenha.backgroundColor = .white
textFieldSenha.delegate = self
return textFieldSenha
}()
private lazy var loginButton: UIButton = {
let loginButton = UIButton()
loginButton.translatesAutoresizingMaskIntoConstraints = false
loginButton.layer.cornerRadius = 3.8
loginButton.titleLabel?.font = UIFont(name: "Arial", size: 19)
loginButton.setTitle("Entrar", for: .normal)
loginButton.setTitleColor(.systemGreen, for: .normal)
loginButton.backgroundColor = .white
return loginButton
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [self.textFieldLogin, self.textFieldSenha, self.loginButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.backgroundColor = .systemBlue
stackView.axis = .vertical
stackView.distribution = .equalSpacing
return stackView
}()
private func viewTapped() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.view.addGestureRecognizer(tapGesture)
}
#objc func handleTap(sender: UITapGestureRecognizer) {
UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: {
self.stackView.frame.origin.y = self.stackView.frame.origin.y + 130
self.textFieldLogin.resignFirstResponder()
self.textFieldSenha.resignFirstResponder()
}, completion: nil)
}
}
extension LoginViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: {
self.stackView.frame.origin.y = self.stackView.frame.origin.y - 130
}, completion: nil)
}
func textFieldDidEndEditing(_ textField: UITextField) {
UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: {
self.stackView.frame.origin.y = self.stackView.frame.origin.y + 130
}, completion: nil)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
I used the following code into textFieldDidBeginEditing and everything works fine! Thank you all.
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded() //Think I forget this method
self.stackView.frame.origin.y = self.stackView.frame.origin.y - 130
}

Animating UITextView cause text disappeared while animation

I am trying to animate UITextView by changing transform. But it makes text disappered while animating. Here is my test code.
class ViewController: UIViewController {
let textView = UITextView()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(textView)
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
textView.heightAnchor.constraint(equalToConstant: 300).isActive = true
textView.backgroundColor = .systemOrange
textView.text = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"
textView.textColor = .white
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeInOut, animations: {
self.textView.transform = CGAffineTransform(translationX: 0, y: 1000)
})
animator.startAnimation()
}
}
}
I tried with storyboard but the result was same. Same result when I use UIView.animate method.
Why does this happen? I want to animate it with text on.
UPDATE
let contraint = textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
contraint.isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
contraint.constant = 1000
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeInOut, animations: {
self.view.layoutIfNeeded()
})
animator.startAnimation()
}
I tested with this code, and got same result.
I'm afraid you'll have to animate a snapshot view instead:
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let v = self.textView.snapshotView(afterScreenUpdates: true)!
v.frame = self.textView.frame
self.view.addSubview(v)
self.textView.isHidden = true
let animator = UIViewPropertyAnimator(duration: 2, curve: .easeInOut, animations: {
v.frame.origin.y = 1000
})
animator.startAnimation()
}
I don't think that's a bad solution; this is what snapshot views are for, after all.

Fold and unfold animation of UIImageView using constraints

As you can see in my code bellow, I'm trying to make a fold/unfold animation using constraints. Certainly the gray background has the fold/unfold animation but the image itself doesn't.
How can I get same fold/unfold effect of the image itself?
class ViewController2: UIViewController {
var folded: Bool = false
var imagen: UIImageView!
private var foldConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let imagen = UIImageView(contentMode: .scaleAspectFill, image: #imageLiteral(resourceName: "gpointbutton"))
imagen.translatesAutoresizingMaskIntoConstraints = false
imagen.backgroundColor = .gray
view.addSubview(imagen)
self.imagen = imagen
imagen.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imagen.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
foldConstraint = imagen.heightAnchor.constraint(equalToConstant: 0)
createAnimationButton()
}
private func createAnimationButton() {
let button = UIButton(title: "Animate", titleColor: .blue)
button.translatesAutoresizingMaskIntoConstraints = false
button.addAction(for: .touchUpInside) { [weak self] (_) in
guard let self = self else { return }
self.folded = !self.folded
if self.folded {
self.foldConstraint.isActive = true
UIView.animate(withDuration: 0.5) {
self.imagen.setNeedsLayout()
self.imagen.superview?.layoutIfNeeded()
}
} else {
self.foldConstraint.isActive = false
UIView.animate(withDuration: 0.5) {
self.imagen.setNeedsLayout()
self.imagen.superview?.layoutIfNeeded()
}
}
}
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
One thing to note here is that the width or height constraint is set to 0 (accurately also includes 0.1), and the same is hidden.
Then you need to set the height constraint to be greater than 0.1
foldConstraint = imagen.heightAnchor.constraint(equalToConstant: 0)
Replace with this, temporarily set to 1
foldConstraint = imagen.heightAnchor.constraint(equalToConstant: 1)
Hide it at the end of the animation
self.folded = !self.folded
if self.folded {
self.foldConstraint.isActive = true
UIView.animate(withDuration: 1, animations: {
self.imagen.setNeedsLayout()
self.imagen.superview?.layoutIfNeeded()
}) { (completion) in
self.imagen.isHidden = true
}
} else {
self.imagen.isHidden = false
self.foldConstraint.isActive = false
UIView.animate(withDuration: 1, animations: {
self.imagen.setNeedsLayout()
self.imagen.superview?.layoutIfNeeded()
})
}
Update:
scaleAspectFill is not suitable for animation, it should be set to scaleAspectFit
let imagen = UIImageView(contentMode: .scaleAspectFit, image: #imageLiteral(resourceName: "gpointbutton"))

How to sort UIView when keyboard appears?

I can't find a good solution of how to move UIView up when the keyboard appears. My solution now is this:
import UIKit
class LoginViewControllerbybys: UIViewController, UITextFieldDelegate {
// Create username and password text boxes
let emailTextField: UITextField = {
let field = UITextField()
field.placeholder = "EMAIL"
field.font = UIFont(name: "Helvetica Neue", size: 14)
field.background = UIImage(named: "divider")
field.autocapitalizationType = .none
field.autocorrectionType = .no
field.spellCheckingType = .no
field.translatesAutoresizingMaskIntoConstraints = false
return field
}()
let passwordTextField: UITextField = {
let field = UITextField()
field.placeholder = "PASSWORD"
field.font = UIFont(name: "Helvetica Neue", size: 14)
field.background = UIImage(named: "divider")
field.autocapitalizationType = .none
field.autocorrectionType = .no
field.spellCheckingType = .no
field.isSecureTextEntry = true
field.translatesAutoresizingMaskIntoConstraints = false
return field
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white // sets background colour to white
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
// Adding Logo in the centre-top of the screen
let logo: UIImageView = {
let image = UIImage(named: "logo")
let imageView = UIImageView(image: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
func logoView() {
logo.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
logo.heightAnchor.constraint(equalToConstant: 75).isActive = true
logo.widthAnchor.constraint(equalToConstant: 75).isActive = true
logo.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
}
func emailTextFieldView() {
emailTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
emailTextField.heightAnchor.constraint(equalToConstant: 35).isActive = true
emailTextField.widthAnchor.constraint(equalToConstant: 310).isActive = true
emailTextField.topAnchor.constraint(equalTo: logo.bottomAnchor, constant: 50).isActive = true
}
func passwordTextFieldView() {
passwordTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
passwordTextField.heightAnchor.constraint(equalToConstant: 35).isActive = true
passwordTextField.widthAnchor.constraint(equalToConstant: 310).isActive = true
passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 30).isActive = true
}
// Create Sign In button
let signInButton: UIButton = {
let button = UIButton()
button.setImage(#imageLiteral(resourceName: "goButton"), for: .normal)
button.frame = CGRect(x: 0, y: 597, width: 375, height: 70)
button.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside) // when tapped on Sign In button, execute function SignInTapped
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
func signInButtonView() {
signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
signInButton.heightAnchor.constraint(equalToConstant: 70).isActive = true
signInButton.widthAnchor.constraint(equalTo: view.widthAnchor, constant: 0).isActive = true
signInButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
// Show all Subviews
self.view.addSubview(logo)
self.view.addSubview(signInButton)
self.view.addSubview(emailTextField)
self.view.addSubview(passwordTextField)
// Constraints
logoView()
signInButtonView()
emailTextFieldView()
passwordTextFieldView()
}
func keyboardWillShow(notification: NSNotification) {
let keyboardSize: CGSize = ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size)!
let offset: CGSize = ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size)!
if keyboardSize.height == offset.height {
if self.view.frame.origin.y == 0 {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y -= keyboardSize.height
})
}
} else {
UIView.animate(withDuration: 0.1, animations: { () -> Void in
self.view.frame.origin.y += keyboardSize.height - offset.height
})
}
}
func keyboardWillHide(notification: NSNotification) {
let keyboardSize: CGSize = ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size)!
self.view.frame.origin.y += keyboardSize.height
}
}
However, the problem with this is that it hides some of my boxes and a label and I can't see them. I thik I would be able to avoid it with UIScrollView but I have no idea how to do it... Would appreciate any help!
You can use UITableView, then you can focus on the selected row using:
scrollToRow(at:at:animated:)
https://developer.apple.com/reference/uikit/uitableview/1614997-scrolltorow

Resources