I have a segment control created programmatically in my RegisterViewController. The registerbutton works and saves everything in a Firebase database but when I switch to the loginbutton, the height of the different textfields is changed but the first one doesn't disappear... There's still a small piece of text visible from the first textfield (as you can see on the picture). Furthermore, when I test the login-function, it doesn't log me in as an existing user but it creates a new user in the database, so I guess it doesn't change the code either...
Login View:
Register View:
import UIKit
import Firebase
class RegisterViewController: UIViewController {
let inputsContainerView: UIView = {
let View = UIView()
View.backgroundColor = UIColor.white
View.translatesAutoresizingMaskIntoConstraints = false
View.layer.cornerRadius = 5
View.layer.masksToBounds = true
return View
}()
lazy var loginRegisterButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(red: 80/255, green: 101/255, blue: 161/255, alpha: 1)
button.setTitle("Register", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(handleRegister), for: .touchUpInside)
return button
}()
func handleLoginRegister() {
if loginRegisterSegmentedControl.selectedSegmentIndex == 0 {
handleLogin()
} else {
handleRegister()
}
}
func handleLogin() {
guard let email = emailTextField.text, let password = passwordTextField.text
else {
print("Form is not valid")
return
}
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
print(error ?? "")
return
}
self.dismiss(animated: true, completion: nil)
})
}
func handleRegister() {
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text
else {
print("Form is not valid")
return
}
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user: FIRUser?, error) in
if error != nil {
print(error ?? "")
return
}
guard let uid = user?.uid else {
return
}
//Succesfully authenticated user
let ref = FIRDatabase.database().reference(fromURL: "https://assemble-148108.firebaseio.com/")
let usersReference = ref.child("users").child(uid)
let values = ["name": name, "email": email]
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err ?? "")
return
}
print("Saved user successfully into Firebase db")
})
})
}
let nameTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Name"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let nameSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(colorLiteralRed: 220/225, green: 220/225, blue: 220/225, alpha: 1)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let emailTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Email"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let emailSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(colorLiteralRed: 220/225, green: 220/225, blue: 220/225, alpha: 1)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let passwordTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Password"
tf.translatesAutoresizingMaskIntoConstraints = false
tf.isSecureTextEntry = true
return tf
}()
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "avatar")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
lazy var loginRegisterSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["Login", "Register"])
sc.translatesAutoresizingMaskIntoConstraints = false
sc.tintColor = UIColor.white
sc.selectedSegmentIndex = 1
sc.addTarget(self, action: #selector(handleLoginRegisterChange), for: .valueChanged)
return sc
}()
func handleLoginRegisterChange() {
let title = loginRegisterSegmentedControl.titleForSegment(at: loginRegisterSegmentedControl.selectedSegmentIndex)
loginRegisterButton.setTitle(title, for: .normal)
// change height of inputContainerView, but how???
inputsContainerViewHeightAnchor?.constant = loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 100 : 150
// change height of nameTextField
nameTextFieldHeightAnchor?.isActive = false
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 0 : 1/3)
nameTextFieldHeightAnchor?.isActive = true
emailTextFieldHeightAnchor?.isActive = false
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
emailTextFieldHeightAnchor?.isActive = true
passwordTextFieldHeightAnchor?.isActive = false
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(colorLiteralRed: 61/225, green: 91/255, blue: 151/255, alpha: 1)
view.addSubview(inputsContainerView)
view.addSubview(loginRegisterButton)
view.addSubview(profileImageView)
view.addSubview(loginRegisterSegmentedControl)
setupInputsContainerView()
setuploginRegisterButton()
setupProfileImageView()
setupRegisterSegmentedControl()
}
//hier moet de kleur van de tijd helemaal bovenaan aangepast worden van zwart naar wit
//override func preferredStatusBarStyle() -> UIStatusBarStyle {
// return .lightContent
//}
func setupRegisterSegmentedControl() {
// need x, y, width, height constraints
loginRegisterSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterSegmentedControl.bottomAnchor.constraint(equalTo:inputsContainerView.topAnchor, constant: -12).isActive = true
loginRegisterSegmentedControl.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor, multiplier: 1).isActive = true
loginRegisterSegmentedControl.heightAnchor.constraint(equalToConstant: 36).isActive = true
}
func setupProfileImageView() {
// need x, y, width, height constraints
profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImageView.bottomAnchor.constraint(equalTo: loginRegisterSegmentedControl.topAnchor, constant: -12).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
var inputsContainerViewHeightAnchor: NSLayoutConstraint?
var nameTextFieldHeightAnchor: NSLayoutConstraint?
var emailTextFieldHeightAnchor: NSLayoutConstraint?
var passwordTextFieldHeightAnchor: NSLayoutConstraint?
func setupInputsContainerView() {
// need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerViewHeightAnchor = inputsContainerView.heightAnchor.constraint(equalToConstant: 150)
inputsContainerViewHeightAnchor?.isActive = true
inputsContainerView.addSubview(nameTextField)
inputsContainerView.addSubview(nameSeparatorView)
inputsContainerView.addSubview(emailTextField)
inputsContainerView.addSubview(emailSeparatorView)
inputsContainerView.addSubview(passwordTextField)
// need x, y, width, height constraints
nameTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
nameTextField.topAnchor.constraint(equalTo: inputsContainerView.topAnchor).isActive = true
nameTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
nameTextFieldHeightAnchor?.isActive = true
// need x, y, width, height constraints
nameSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
nameSeparatorView.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
nameSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
// need x, y, width, height constraints
emailTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
emailTextField.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
emailTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
emailTextFieldHeightAnchor?.isActive = true
// need x, y, width, height constraints
emailSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
emailSeparatorView.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true
emailSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
emailSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
// need x, y, width, height constraints
passwordTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true
passwordTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
func setuploginRegisterButton() {
// need x, y, width, height constraints
loginRegisterButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterButton.topAnchor.constraint(equalTo: inputsContainerView.bottomAnchor, constant: 12).isActive = true
loginRegisterButton.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
loginRegisterButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
}
If you want a quick fix, you set the nameTextField to be hidden
if loginRegisterSegmentedControl.selectedSegmentIndex == 0 {
nameTextField.isHidden = true
} else {
nameTextField.isHidden = false
}
Do this in the func handleLoginRegisterChange().
Also you don't need func handleLoginRegister(), it doesn't seem to be used.
If you want a proper fix, when you switch segments, you should remove the name label and redo the constraints.
Related
I have a basic sign up screen set up programmatically with the UI elements inside a view that is itself inside a scroll view.
The last UI element in the screen is a register button. I set up a keyboard notification observer with the Will Show and Will Hide notifications.
I am running this code on iPod touch 7th gen simulator.
My problem is when trying to read the maxY value of the sign up button and compare it to the keyboard minY it prints wrong numbers.
The keyboard is clearly blocking the register button which mean the button's maxY value will be greater the the keyboard minY value.
However the values printed shows that there is something wrong with the reading of the register button frame.
Here is my code:
import UIKit
class RegisterVC: UIViewController {
private let scrollView: UIScrollView = {
let scroll = UIScrollView()
scroll.clipsToBounds = true
scroll.isScrollEnabled = true
scroll.translatesAutoresizingMaskIntoConstraints = false
scroll.showsVerticalScrollIndicator = false
return scroll
}()
private let scrollInnerView: UIView = {
let innerView = UIView()
innerView.translatesAutoresizingMaskIntoConstraints = false
return innerView
}()
private let profilePic: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(systemName: "person.circle")
imageView.contentMode = .scaleAspectFit
imageView.tintColor = .gray
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
private let usernameField: UITextField = {
let field = UITextField()
field.autocapitalizationType = .none
field.autocorrectionType = .no
field.returnKeyType = .next
field.layer.cornerRadius = 12
field.layer.borderWidth = 1
field.layer.borderColor = UIColor.lightGray.cgColor
field.placeholder = "Username..."
field.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 0))
field.leftViewMode = .always
field.backgroundColor = .white
field.keyboardType = .default
field.isHighlighted = false
field.textAlignment = .left
field.translatesAutoresizingMaskIntoConstraints = false
return field
}()
private let emailField: UITextField = {
let field = UITextField()
field.autocapitalizationType = .none
field.autocorrectionType = .no
field.returnKeyType = .next
field.layer.cornerRadius = 12
field.layer.borderWidth = 1
field.layer.borderColor = UIColor.lightGray.cgColor
field.placeholder = "Email Address..."
field.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 0))
field.leftViewMode = .always
field.backgroundColor = .white
field.keyboardType = .default
field.textAlignment = .left
field.translatesAutoresizingMaskIntoConstraints = false
return field
}()
private let passwordField: UITextField = {
let field = UITextField()
field.autocapitalizationType = .none
field.autocorrectionType = .no
field.returnKeyType = .done
field.layer.cornerRadius = 12
field.layer.borderWidth = 1
field.layer.borderColor = UIColor.lightGray.cgColor
field.placeholder = "Password..."
field.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 0))
field.leftViewMode = .always
field.backgroundColor = .white
field.isSecureTextEntry = true
field.textAlignment = .left
field.keyboardType = .default
field.translatesAutoresizingMaskIntoConstraints = false
return field
}()
private let registerButton: UIButton = {
let button = UIButton()
button.setTitle("Create Account", for: .normal)
button.backgroundColor = .systemGreen
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 12
button.layer.masksToBounds = true
button.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
title = "Create Account"
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.addSubview(scrollInnerView)
scrollInnerView.addSubview(profilePic)
scrollInnerView.addSubview(usernameField)
scrollInnerView.addSubview(emailField)
scrollInnerView.addSubview(passwordField)
scrollInnerView.addSubview(registerButton)
usernameField.delegate = self
emailField.delegate = self
passwordField.delegate = self
profilePic.isUserInteractionEnabled = true
registerButton.addTarget(self,
action: #selector(registerButtonTapped),
for: .touchUpInside)
setUpKeyboard()
setUpConstraints()
}
private func setUpConstraints() {
// Scroll View Constraints
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// Scroll Inner View Constraints
scrollInnerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollInnerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
scrollInnerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
scrollInnerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
scrollInnerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
scrollInnerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor, constant: 1).isActive = true
// Profile Picture Constraints
profilePic.widthAnchor.constraint(equalTo: scrollInnerView.widthAnchor, multiplier: 1/3).isActive = true
profilePic.heightAnchor.constraint(equalTo: scrollInnerView.widthAnchor, multiplier: 1/3).isActive = true
profilePic.centerXAnchor.constraint(equalTo: scrollInnerView.centerXAnchor).isActive = true
profilePic.topAnchor.constraint(equalTo: scrollInnerView.topAnchor, constant: 10).isActive = true
// User Name Field Constraints
usernameField.widthAnchor.constraint(equalTo: scrollInnerView.widthAnchor, constant: -60).isActive = true
usernameField.heightAnchor.constraint(equalToConstant: 45).isActive = true
usernameField.topAnchor.constraint(equalTo: profilePic.bottomAnchor, constant: 10).isActive = true
usernameField.centerXAnchor.constraint(equalTo: profilePic.centerXAnchor).isActive = true
// Email Field Constraints
emailField.widthAnchor.constraint(equalTo: usernameField.widthAnchor).isActive = true
emailField.heightAnchor.constraint(equalTo: usernameField.heightAnchor).isActive = true
emailField.topAnchor.constraint(equalTo: usernameField.bottomAnchor, constant: 10).isActive = true
emailField.centerXAnchor.constraint(equalTo: usernameField.centerXAnchor).isActive = true
// Password Field Constraints
passwordField.widthAnchor.constraint(equalTo: emailField.widthAnchor).isActive = true
passwordField.heightAnchor.constraint(equalTo: emailField.heightAnchor).isActive = true
passwordField.topAnchor.constraint(equalTo: emailField.bottomAnchor, constant: 10).isActive = true
passwordField.centerXAnchor.constraint(equalTo: emailField.centerXAnchor).isActive = true
// Register Button Constraints
registerButton.widthAnchor.constraint(equalTo: passwordField.widthAnchor).isActive = true
registerButton.heightAnchor.constraint(equalTo: passwordField.heightAnchor).isActive = true
registerButton.topAnchor.constraint(equalTo: passwordField.bottomAnchor, constant: 20).isActive = true
registerButton.centerXAnchor.constraint(equalTo: passwordField.centerXAnchor).isActive = true
}
private func setUpKeyboard() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc private func keyboardWillShowNotification(_ notification: NSNotification) {
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
else {
return
}
print(keyboardSize.minY)
print(registerButton.frame.maxY)
}
}
It's because the keyboard frame and the button frame are in two different coordinate systems. You cannot compare them directly. You need to convert the button frame to window coordinates before comparing them. Or else convert the keyboard frame to the button frame coordinates (the button's superview).
Actually what I typically do is convert the keyboard frame to the internal coordinates of the target view and compare that to the target view's bounds. For example:
// n is the notification
let d = n.userInfo!
var r = d[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
r = self.slidingView.convert(r, from:nil) // <- this is the key move!
let h = self.slidingView.bounds.intersection(r).height
That tells me whether the keyboard would cover the sliding view, and if so, by how much.
I have a collectionView for display posts, I have 3 different post types (Text,Image and Video). I`ve added an imageview to cell and Im using if else codes in cellForItemAt function for display imageview for Image and Video posts or hide it with heightAnchor = 0 for text posts.
its loading correct at beginning, but when I scroll down and scroll up again images heightAnchor resetting to "0" for every posts. How can I solve this issue ?
When the posts are loaded
When I Scroll down and scroll up again
TimelinePosts CollectionViewCell
class TimelinePosts: UICollectionViewCell {
let avatar: UIImageView = {
let avatar = UIImageView()
avatar.contentMode = .scaleAspectFill
avatar.clipsToBounds = true
avatar.layer.cornerRadius = 24
avatar.translatesAutoresizingMaskIntoConstraints = false
return avatar
}()
let name: UILabel = {
let name = UILabel()
name.numberOfLines = 1
name.translatesAutoresizingMaskIntoConstraints = false
return name
}()
let content: ActiveLabel = {
let content = ActiveLabel()
content.numberOfLines = 0
content.font = UIFont.systemFont(ofSize: 15)
content.translatesAutoresizingMaskIntoConstraints = false
return content
}()
let image: UIImageView = {
let image = UIImageView()
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.layer.cornerRadius = 12
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
let time: UILabel = {
let time = UILabel()
time.numberOfLines = 1
time.textColor = .gray
time.font = UIFont.systemFont(ofSize: 14)
time.textAlignment = .center
time.translatesAutoresizingMaskIntoConstraints = false
return time
}()
let moreButton: UIButton = {
let button = UIButton()
let image = UIImage(named: "arrow")
button.setImage(image, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let favoriteButton: FaveButton = {
let button = FaveButton(frame: CGRect(x:0, y:0, width: 28, height: 28), faveIconNormal: UIImage(named: "favorite"))
button.normalColor = UIColor(hexString: "#CBCBCB")
button.selectedColor = UIColor(hexString: "#FFBE00")
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let boostButton: FaveButton = {
let button = FaveButton(frame: CGRect(x:0, y:0, width: 28, height: 28), faveIconNormal: UIImage(named: "boost-pressed"))
button.normalColor = UIColor(hexString: "#CBCBCB")
button.selectedColor = UIColor(hexString: "#6e00ff")
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let actions: UILabel = {
let view = UILabel()
view.numberOfLines = 1
view.textAlignment = .left
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
addViews()
setupViews()
}
func addViews(){
addSubview(avatar)
addSubview(moreButton)
addSubview(time)
addSubview(name)
addSubview(content)
addSubview(image)
addSubview(favoriteButton)
addSubview(boostButton)
addSubview(actions)
}
func setupViews(){
avatar.leftAnchor.constraint(equalTo: leftAnchor, constant: 15).isActive = true
avatar.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
avatar.widthAnchor.constraint(equalToConstant: 48).isActive = true
avatar.heightAnchor.constraint(equalToConstant: 48).isActive = true
moreButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -18).isActive = true
moreButton.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
moreButton.widthAnchor.constraint(equalToConstant: 14).isActive = true
moreButton.heightAnchor.constraint(equalToConstant: 14).isActive = true
time.leftAnchor.constraint(equalTo: leftAnchor, constant: 15).isActive = true
time.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
time.widthAnchor.constraint(equalToConstant: 48).isActive = true
time.heightAnchor.constraint(equalToConstant: 20).isActive = true
name.leftAnchor.constraint(equalTo: avatar.rightAnchor, constant: 10).isActive = true
name.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: -14).isActive = true
name.topAnchor.constraint(equalTo: topAnchor, constant: 15).isActive = true
name.heightAnchor.constraint(equalToConstant: 20).isActive = true
content.leftAnchor.constraint(equalTo: leftAnchor, constant: 73).isActive = true
content.rightAnchor.constraint(equalTo: rightAnchor, constant: -46).isActive = true
content.topAnchor.constraint(equalTo: name.bottomAnchor, constant: 5).isActive = true
image.leftAnchor.constraint(equalTo: leftAnchor, constant: 73).isActive = true
image.rightAnchor.constraint(equalTo: rightAnchor, constant: -46).isActive = true
image.topAnchor.constraint(equalTo: content.bottomAnchor, constant: 5).isActive = true
image.heightAnchor.constraint(equalToConstant: ((UIScreen.main.bounds.width - 120) * 2) / 3).isActive = true
actions.leftAnchor.constraint(equalTo: avatar.rightAnchor, constant: 10).isActive = true
actions.rightAnchor.constraint(equalTo: moreButton.leftAnchor, constant: -14).isActive = true
actions.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 10).isActive = true
actions.heightAnchor.constraint(equalToConstant: 20).isActive = true
actions.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
favoriteButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -14).isActive = true
favoriteButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
favoriteButton.widthAnchor.constraint(equalToConstant: 20).isActive = true
favoriteButton.heightAnchor.constraint(equalToConstant: 20).isActive = true
boostButton.rightAnchor.constraint(equalTo: rightAnchor, constant: -14).isActive = true
boostButton.bottomAnchor.constraint(equalTo: favoriteButton.topAnchor, constant: -12).isActive = true
boostButton.widthAnchor.constraint(equalToConstant: 20).isActive = true
boostButton.heightAnchor.constraint(equalToConstant: 20).isActive = true
/* name.backgroundColor = .yellow
content.backgroundColor = .red
image.backgroundColor = .green */
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And cellForItemAt function
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TimelinePosts", for: indexPath) as! TimelinePosts
if indexPath.row < id.count{
cell.avatar.sd_setImage(with: URL(string: avatars[indexPath.row]))
cell.time.text = hours[indexPath.row]
cell.favoriteButton.isSelected = isLike[indexPath.row]
cell.favoriteButton.isUserInteractionEnabled = true
cell.favoriteButton.tag = indexPath.row
cell.boostButton.isSelected = isBoost[indexPath.row]
cell.boostButton.isUserInteractionEnabled = true
cell.boostButton.tag = indexPath.row
let selectedArrowTap = UITapGestureRecognizer(target: self, action: #selector(self.selectedArrow))
selectedArrowTap.numberOfTapsRequired = 1
cell.moreButton.isUserInteractionEnabled = true
cell.moreButton.tag = indexPath.row
cell.moreButton.addGestureRecognizer(selectedArrowTap)
cell.content.customize { label in
label.text = content[indexPath.row]
label.hashtagColor = UIColor(hexString: "#6e00ff")
label.mentionColor = UIColor(hexString: "#6e00ff")
label.URLColor = UIColor(hexString: "#0366d6")
}
cell.content.handleHashtagTap { hashtag in
print("Success. You just tapped the \(hashtag) hashtag")
}
cell.content.handleURLTap { url in
let urlString = url.absoluteString
if urlString.hasPrefix("http://")
{
let openURL = URL(string: urlString)!
let svc = SFSafariViewController(url: openURL)
self.present(svc, animated: true, completion: nil)
}
else if urlString.hasPrefix("https://")
{
let openURL = URL(string: urlString)!
let svc = SFSafariViewController(url: openURL)
self.present(svc, animated: true, completion: nil)
}
else
{
let openURL = URL(string: "https://" + urlString)!
let svc = SFSafariViewController(url: openURL)
self.present(svc, animated: true, completion: nil)
}
}
if types[indexPath.row] == 2{
cell.image.sd_setImage(with: URL(string: images[indexPath.row]))
let selectedImageTap = UITapGestureRecognizer(target: self, action: #selector(self.photoZoom))
selectedImageTap.numberOfTapsRequired = 1
cell.image.isUserInteractionEnabled = true
cell.image.tag = indexPath.row
cell.image.addGestureRecognizer(selectedImageTap)
}else if types[indexPath.row] == 3{
cell.image.sd_setImage(with: URL(string: "https://i.ytimg.com/vi/\(self.extractYoutubeIdFromLink(link: videos[indexPath.row])!)/mqdefault.jpg"))
let playBtn = UIImageView()
playBtn.image = UIImage(named: "youtube-play")
playBtn.tag = indexPath.row
playBtn.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.videoPlay)))
playBtn.isUserInteractionEnabled = true
playBtn.translatesAutoresizingMaskIntoConstraints = false
cell.image.isUserInteractionEnabled = true
cell.image.addSubview(playBtn)
playBtn.centerXAnchor.constraint(equalTo: cell.image.centerXAnchor).isActive = true
playBtn.centerYAnchor.constraint(equalTo: cell.image.centerYAnchor).isActive = true
playBtn.widthAnchor.constraint(equalToConstant: 74).isActive = true
playBtn.heightAnchor.constraint(equalToConstant: 52).isActive = true
}else{
cell.image.heightAnchor.constraint(equalToConstant: 0).isActive = true
}
}
return cell
}
you should not modify image height by
cell.image.heightAnchor.constraint(equalToConstant: 0).isActive = true
create a new variable imageHeightConstraint in you TimelinesPosts,
set this variable in setupViews()
imageHeightConstraint = image.heightAnchor.constraint(equalToConstant: ((UIScreen.main.bounds.width - 120) * 2) / 3).isActive = true
then change the height by this
// don't miss this code.
imageHeightConstraint.constant = ((UIScreen.main.bounds.width - 120) * 2) / 3
if types[indexPath.row] == 2 {
//***************
} else if types[indexPath.row] == 3 {
//***************
} else {
imageHeightConstraint.constant = 0
}
UIScrollView is parent UICollectionView. You use UIScrollView with UIScrollViewDelegate for setup images with va scrollOffset: CGFloat follow .y (referent code)
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var scrollOffset : CGFloat = scrollView.contentOffset.y
// process with scrollOffset
}
}
I am creating a chat layout to display cell for incoming and outgoing kind of messages. I have been able to make it work by activating and deactivating Constraints, except for the Text Message Kind. I noticed that on prepareForReuse() the constraints for outgoing cell get distorted.
I will like to know how I can fix this or a better alternative to solve the problem.
This is a video of what happens when I scroll.
TextMessageCell.swift
class TextMessageCell: ChatBaseCell {
override var viewModel: ChatCommonRepresentable? {
didSet {
guard let viewModel = viewModel as? MessageModel else {return}
let isIncoming = viewModel.isIncomming
messageLabel.text = viewModel.message
self.message = viewModel.message
sentLabel.text = viewModel.sentDateString
bubbleBackgroundView.backgroundColor = isIncoming ? .white : Color.solid08.value
messageLabel.textColor = isIncoming ? .black : .white
if isIncoming {
leadingConstraint.isActive = true
trailingConstraint.isActive = false
} else {
sentLabel.setTicker(status: viewModel.status)
leadingConstraint.isActive = false
trailingConstraint.isActive = true
}
}
}
private lazy var messageLabel: UITextViewFixed = {
let label = UITextViewFixed()
label.textAlignment = .left
label.isEditable = false
label.backgroundColor = .clear
label.isScrollEnabled = false
label.dataDetectorTypes = [.flightNumber, .calendarEvent, .address, .phoneNumber, .link, .lookupSuggestion]
label.isSelectable = true
label.isUserInteractionEnabled = true
label.delaysContentTouches = true
label.font = Font(.installed(.OpenSansRegular), size: .standard(.bodySmall)).instance
label.linkTextAttributes?[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.single
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var sentLabel: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.textColor = Color.custom(hexString: "#C8CAD3", alpha: 1.0).value
label.font = Font(.installed(.OpenSansSemiBold), size: .custom(10)).instance
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var bubbleBackgroundView: UIView = {
let view = UIView()
view.layer.cornerRadius = 12
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!
var widthConstraint: NSLayoutConstraint!
var widthFullConstraint: NSLayoutConstraint!
var sentLabelBottomConstraint: NSLayoutConstraint!
var sentLabelCenterYConstraint: NSLayoutConstraint!
var messageLabelBottomConstraint: NSLayoutConstraint!
var messageLabelCenterYConstraint: NSLayoutConstraint!
var messageLabelTopConstraint: NSLayoutConstraint!
var message: String! {
didSet {
let constantHeight: CGFloat = message.height(withConstrainedWidth: 250 - 32 - 8, font: Font(.installed(.OpenSansRegular), size: .standard(.bodySmall)).instance)
let constantWidth: CGFloat = message.width(withConstrainedHeight: constantHeight, font: Font(.installed(.OpenSansRegular), size: .standard(.bodySmall)).instance)
print(constantWidth)
if constantHeight < 21 {
if constantWidth > 230 {
sentLabelCenterYConstraint.isActive = false
sentLabelBottomConstraint.isActive = true
messageLabelTopConstraint.isActive = true
messageLabelCenterYConstraint.isActive = false
messageLabelBottomConstraint.isActive = true
widthConstraint = bubbleBackgroundView.widthAnchor.constraint(lessThanOrEqualToConstant: 250)
widthConstraint.isActive = true
} else {
sentLabelCenterYConstraint.isActive = true
sentLabelBottomConstraint.isActive = false
messageLabelTopConstraint.isActive = false
messageLabelCenterYConstraint.isActive = true
messageLabelBottomConstraint.isActive = false
guard let user = UserDefaults().currentUser() else {return}
let isIncoming = "\(user.id!)" != viewModel!.sender.id
if isIncoming {
let fullWidth = constantWidth + 70
widthFullConstraint.constant = fullWidth
widthFullConstraint.isActive = true
} else {
let fullWidth = constantWidth + 90
widthFullConstraint.constant = fullWidth
widthFullConstraint.isActive = true
}
}
}
}
}
private func constraintViews() {
}
override func setupViews() {
addSubview(bubbleBackgroundView)
bubbleBackgroundView.addSubview(messageLabel)
bubbleBackgroundView.addSubview(sentLabel)
bubbleBackgroundView.topAnchor.align(to: topAnchor)
bubbleBackgroundView.bottomAnchor.align(to: bottomAnchor)
messageLabel.trailingAnchor.align(to: bubbleBackgroundView.trailingAnchor, offset: -8)
messageLabel.leadingAnchor.align(to: bubbleBackgroundView.leadingAnchor, offset: 8)
sentLabel.trailingAnchor.align(to: bubbleBackgroundView.trailingAnchor, offset: -10)
sentLabel.widthAnchor.equal(to: 70)
leadingConstraint = bubbleBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20)
leadingConstraint.isActive = false
trailingConstraint = bubbleBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20)
trailingConstraint.isActive = true
widthConstraint = bubbleBackgroundView.widthAnchor.constraint(lessThanOrEqualToConstant: 250)
widthConstraint.isActive = true
widthFullConstraint = bubbleBackgroundView.widthAnchor.constraint(equalToConstant: 1)
widthFullConstraint.isActive = false
messageLabelTopConstraint = messageLabel.topAnchor.constraint(equalTo: bubbleBackgroundView.topAnchor, constant: 10)
messageLabelTopConstraint.isActive = false
messageLabelBottomConstraint = bubbleBackgroundView.bottomAnchor.constraint(equalTo: bubbleBackgroundView.bottomAnchor, constant: -18)
messageLabelBottomConstraint.isActive = true
messageLabelCenterYConstraint = messageLabel.centerYAnchor.constraint(equalTo: bubbleBackgroundView.centerYAnchor)
messageLabelCenterYConstraint.isActive = false
sentLabelBottomConstraint = sentLabel.bottomAnchor.constraint(equalTo: bubbleBackgroundView.bottomAnchor, constant: -8)
sentLabelBottomConstraint.isActive = true
sentLabelCenterYConstraint = sentLabel.centerYAnchor.constraint(equalTo: bubbleBackgroundView.centerYAnchor)
sentLabelCenterYConstraint.isActive = false
}
override func prepareForReuse() {
super.prepareForReuse()
sentLabel.text = nil
messageLabel.text = nil
leadingConstraint.isActive = false
trailingConstraint.isActive = false
widthConstraint.isActive = false
sentLabelBottomConstraint.isActive = false
sentLabelCenterYConstraint.isActive = false
messageLabelBottomConstraint.isActive = false
messageLabelCenterYConstraint.isActive = false
messageLabelTopConstraint.isActive = false
widthFullConstraint.isActive = false
}
}
How can i use activity Indicator in the following code when a user registers or logs in the message view.
The Code below is a loginViewController which handles the login and Registeration of the User.
so, How can i use Activity Indicator View or Progress view PROGRAMATICALLY whenever a user hits the Login or Register Button .
class LoginController: UIViewController {
var messagesController: MessagesController?
let inputsContainerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 209, g:238, b:252).withAlphaComponent(0.3)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
return view
}()
lazy var loginRegisterButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(r: 255, g: 45, b: 85)
button.setTitle("Register", for: UIControlState())
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(UIColor.white, for: UIControlState())
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.layer.cornerRadius = 10
button.addTarget(self, action: #selector(handleLoginRegister), for: .touchUpInside)
return button
}()
func handleLoginRegister() {
if loginRegisterSegmentedControl.selectedSegmentIndex == 0 {
handleLogin()
} else {
handleRegister()
}
}
func handleLogin() {
guard let email = emailTextField.text, let password = passwordTextField.text else {
print("Form is not valid")
return
}
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
print(error ?? "")
return
}
//successfully logged in our user
self.messagesController?.fetchUserAndSetupNavBarTitle()
self.dismiss(animated: true, completion: nil)
})
}
// TextField, EmailTextField, PasswordTextField, seperator view
let nameTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Name"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let nameSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let emailTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Email"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let emailSeparatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let passwordTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Password"
tf.translatesAutoresizingMaskIntoConstraints = false
tf.isSecureTextEntry = true
return tf
}()
lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "backslash_inc02main")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 20
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var loginRegisterSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["Login", "Register"])
sc.translatesAutoresizingMaskIntoConstraints = false
sc.tintColor = UIColor.white
sc.selectedSegmentIndex = 1
sc.addTarget(self, action: #selector(handleLoginRegisterChange), for: .valueChanged)
return sc
}()
func handleLoginRegisterChange() {
let title = loginRegisterSegmentedControl.titleForSegment(at: loginRegisterSegmentedControl.selectedSegmentIndex)
loginRegisterButton.setTitle(title, for: UIControlState())
// change height of inputContainerView, but how???
inputsContainerViewHeightAnchor?.constant = loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 100 : 150
// change height of nameTextField
nameTextFieldHeightAnchor?.isActive = false
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 0 : 1/3)
nameTextFieldHeightAnchor?.isActive = true
nameTextField.isHidden = loginRegisterSegmentedControl.selectedSegmentIndex == 0
emailTextFieldHeightAnchor?.isActive = false
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
emailTextFieldHeightAnchor?.isActive = true
passwordTextFieldHeightAnchor?.isActive = false
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
//view.backgroundColor = UIColor(r: 255, g: 149, b: 0)
self.view.addBackground()
view.addSubview(inputsContainerView)
view.addSubview(loginRegisterButton)
view.addSubview(profileImageView)
view.addSubview(loginRegisterSegmentedControl)
setupInputsContainerView()
setupLoginRegisterButton()
setupProfileImageView()
setupLoginRegisterSegmentedControl()
}
func setupLoginRegisterSegmentedControl() {
//need x, y, width, height constraints
loginRegisterSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterSegmentedControl.bottomAnchor.constraint(equalTo: inputsContainerView.topAnchor, constant: -12).isActive = true
loginRegisterSegmentedControl.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor, multiplier: 1).isActive = true
loginRegisterSegmentedControl.heightAnchor.constraint(equalToConstant: 36).isActive = true
}
func setupProfileImageView() {
//need x, y, width, height constraints
profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImageView.bottomAnchor.constraint(equalTo: loginRegisterSegmentedControl.topAnchor, constant: -12).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 150).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
}
var inputsContainerViewHeightAnchor: NSLayoutConstraint?
var nameTextFieldHeightAnchor: NSLayoutConstraint?
var emailTextFieldHeightAnchor: NSLayoutConstraint?
var passwordTextFieldHeightAnchor: NSLayoutConstraint?
func setupInputsContainerView() {
//need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerViewHeightAnchor = inputsContainerView.heightAnchor.constraint(equalToConstant: 150)
inputsContainerViewHeightAnchor?.isActive = true
inputsContainerView.addSubview(nameTextField)
inputsContainerView.addSubview(nameSeparatorView)
inputsContainerView.addSubview(emailTextField)
inputsContainerView.addSubview(emailSeparatorView)
inputsContainerView.addSubview(passwordTextField)
//need x, y, width, height constraints
nameTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
nameTextField.topAnchor.constraint(equalTo: inputsContainerView.topAnchor).isActive = true
nameTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
nameTextFieldHeightAnchor?.isActive = true
//need x, y, width, height constraints
nameSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
nameSeparatorView.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
nameSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
//need x, y, width, height constraints
emailTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
emailTextField.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
emailTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
emailTextFieldHeightAnchor = emailTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
emailTextFieldHeightAnchor?.isActive = true
//need x, y, width, height constraints
emailSeparatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
emailSeparatorView.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true
emailSeparatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
emailSeparatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
//need x, y, width, height constraints
passwordTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor).isActive = true
passwordTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
func setupLoginRegisterButton() {
//need x, y, width, height constraints
loginRegisterButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterButton.topAnchor.constraint(equalTo: inputsContainerView.bottomAnchor, constant: 12).isActive = true
loginRegisterButton.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
loginRegisterButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
}
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
}
}
To show activity indicator, first declare it at class level and then initialize it.
var activityIndicator:UIActivityIndicatorView!
Then in your viewdidLoad() method, initialize activityIndicator.
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicator.center = view.center
activityIndicator.isHidden = true
self.view.addSubview(activityIndicator)
You can write two methods to start and stop activity indicator in your view controller as:
func displayActivityIndicatorView() -> () {
UIApplication.shared.beginIgnoringInteractionEvents()
self.view.bringSubview(toFront: self.activityIndicator)
self.activityIndicator.isHidden = false
self.activityIndicator.startAnimating()
}
func hideActivityIndicatorView() -> () {
if !self.activityIndicator.isHidden{
DispatchQueue.main.async {
UIApplication.shared.endIgnoringInteractionEvents()
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
}
}
Now start activity indicator just after validating the login data and before hitting the login API as:
func handleLogin() {
guard let email = emailTextField.text, let password = passwordTextField.text else {
print("Form is not valid")
return
}
//start activity indicator
self. displayActivityIndicatorView()
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
print(error ?? "")
//stop activity indicator
self. hideActivityIndicatorView()
return
}
//successfully logged in our user
//stop activity indicator
self. hideActivityIndicatorView()
self.messagesController?.fetchUserAndSetupNavBarTitle()
self.dismiss(animated: true, completion: nil)
})
}
Step 1:
Create activity indicator somewhere in your code. Specially in viewDidLoad
if you want to create it programmatically or if you want to show activity indicator with an alert design in programmatically.
Step 2: To show activity indicator
There is a button like login or register . There you will start the to show the activity indicator and start it to animate.
Step 3: To hide activity indicator
You will hide activity indicator in FIRAuth.auth()?.signIn..... completion handler for login. just like
[indicator stopAnimating];
[indicator isHidden:YES];
There are two cases in that login method. one is error and the other is successful. Its better to show an error alert to the user or something else.
Hope you will find this solution helpful. :)
You can use below code.
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
alert.view.tintColor = UIColor.black
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x:10, y:5, width:50, height:50)) as UIActivityIndicatorView
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.color = UIColor(red: 255.0/255, green: 65.0/255, blue: 42.0/255,alpha : 1.0)
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
///dismisss///
dismiss(animated: false, completion: nil)
I am having trouble setting up a scroll view and actually scrolling down. I populated the scroll view with some textfields and used anchors (topanchor,leftanchor...) to position them inside the scroll view. Even if I set the scroll view height to 1000, it wont actually move, it continues to show the same items, the scroll indicator does go down but the content itself doesnt, I already set the scroll view to scrollenabled, and delegate to self.
I think the problem might be with the anchors but then how will I arrange my items inside the scroll view, any sugestion will be greatly appreaciated.
EDIT : The code below indicates the anchors applied to the scroll view ( inputContainer ), the img corresponds to an UIImageView and the mainContainer to the UIView containing the img and the inputContainer.
inputContainer.topAnchor.constraintEqualToAnchor( img.bottomAnchor ).active = true
inputContainer.leftAnchor.constraintEqualToAnchor( mainContainer.leftAnchor ).active = true
inputContainer.widthAnchor.constraintEqualToAnchor( mainContainer.widthAnchor ).active = true
inputContainerBottomConstraint = inputContainer.bottomAnchor.constraintEqualToAnchor( cancelButton.topAnchor )
inputContainerBottomConstraint?.active = true
EDIT: This is how the code looks like :
class SView : UIView, UITextFieldDelegate, UIScrollViewDelegate {
let mainContainer : UIView = {
let v = UIView()
v.backgroundColor = .whiteColor()
v.layer.cornerRadius = 8
v.layer.masksToBounds = true
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let Img : UIImageView = {
let img = UIImageView()
img.image = UIImage(named: "noImage")
img.backgroundColor = .blueColor()
img.translatesAutoresizingMaskIntoConstraints = false
img.contentMode = .ScaleAspectFill
img.clipsToBounds = true
return img
}()
let inputContainer : UIScrollView = {
let ic = UIScrollView()
ic.backgroundColor = .whiteColor()
ic.translatesAutoresizingMaskIntoConstraints = false
return ic
}()
let datePickerTextField : UITextField = {
let tf = UITextField()
tf.placeholder = "Fecha"
tf.textAlignment = .Center
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let tagsTextField : UITextField = {
let tf = UITextField()
tf.placeholder = "Tags"
tf.textAlignment = .Center
tf.clearButtonMode = .Always
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
lazy var cancelButton : UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.rgb(255, green: 65, blue: 65, alpha: 1)
button.setTitle("Cancelar", forState: .Normal)
button.tintColor = .whiteColor()
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget( self , action: #selector(handleCancelButtonPressed), forControlEvents: .TouchUpInside)
return button
}()
lazy var publicarButton : UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.rgb(0 , green: 204, blue: 102, alpha: 1)
button.setTitle("Publicar", forState: .Normal)
button.tintColor = .whiteColor()
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget( self , action: #selector(handlePublicarButtonPressed), forControlEvents: .TouchUpInside)
return button
}()
override init(frame: CGRect)
{
super.init(frame: frame)
inputContainer.delegate = self
datePickerTextField.delegate = self
tagsTextField.delegate = self
setupMainContainer()
setupImg()
setupButtons()
setupInputContainer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupMainContainer ()
{
addSubview(mainContainer)
mainContainer.centerXAnchor.constraintEqualToAnchor( centerXAnchor ).active = true
mainContainer.centerYAnchor.constraintEqualToAnchor( centerYAnchor ).active = true
mainContainer.widthAnchor.constraintEqualToAnchor( widthAnchor ).active = true
mainContainer.heightAnchor.constraintEqualToAnchor( heightAnchor )
}
func setupImg ()
{
mainContainer.addSubview(Img)
Img.topAnchor.constraintEqualToAnchor( mainContainer.topAnchor ).active = true
Img.leftAnchor.constraintEqualToAnchor( mainContainer.leftAnchor ).active = true
Img.widthAnchor.constraintEqualToAnchor( mainContainer.widthAnchor ).active = true
Img.heightAnchor.constraintEqualToAnchor( mainContainer.heightAnchor , multiplier: 0.3).active = true
}
var inputContainerBottomConstraint : NSLayoutConstraint?
func setupInputContainer ()
{
mainContainer.addSubview(inputContainer)
inputContainer.topAnchor.constraintEqualToAnchor( Img.bottomAnchor ).active = true
inputContainer.leftAnchor.constraintEqualToAnchor( mainContainer.leftAnchor ).active = true
inputContainer.rightAnchor.constraintEqualToAnchor( mainContainer.rightAnchor ).active = true
inputContainerBottomConstraint = inputContainer.bottomAnchor.constraintEqualToAnchor( cancelButton.topAnchor )
inputContainerBottomConstraint?.active = true
inputContainer.addSubview( datePickerTextField )
inputContainer.addSubview( tagsTextField )
datePickerTextField.topAnchor.constraintEqualToAnchor( inputContainer.topAnchor ).active = true
datePickerTextField.centerXAnchor.constraintEqualToAnchor( inputContainer.centerXAnchor ).active = true
datePickerTextField.widthAnchor.constraintEqualToAnchor( inputContainer.widthAnchor ).active = true
datePickerTextField.heightAnchor.constraintEqualToAnchor( inputContainer.heightAnchor, multiplier: 0.2 ).active = true
tagsTextField.bottomAnchor.constraintEqualToAnchor( inputContainer.bottomAnchor ).active = true
tagsTextField.centerXAnchor.constraintEqualToAnchor( inputContainer.centerXAnchor ).active = true
tagsTextField.widthAnchor.constraintEqualToAnchor( inputContainer.widthAnchor ).active = true
tagsTextField.heightAnchor.constraintEqualToAnchor( inputContainer.heightAnchor, multiplier: 0.2 ).active = true
}
func setupButtons()
{
mainContainer.addSubview( cancelButton )
mainContainer.addSubview( publicarButton )
cancelButton.bottomAnchor.constraintEqualToAnchor( mainContainer.bottomAnchor).active = true
cancelButton.leftAnchor.constraintEqualToAnchor( mainContainer.leftAnchor ).active = true
cancelButton.widthAnchor.constraintEqualToAnchor( mainContainer.widthAnchor, multiplier: 0.5 ).active = true
cancelButton.heightAnchor.constraintEqualToAnchor( mainContainer.heightAnchor, multiplier: 0.1).active = true
publicarButton.bottomAnchor.constraintEqualToAnchor( mainContainer.bottomAnchor).active = true
publicarButton.leftAnchor.constraintEqualToAnchor( cancelButton.rightAnchor ).active = true
publicarButton.widthAnchor.constraintEqualToAnchor( mainContainer.widthAnchor, multiplier: 0.5 ).active = true
publicarButton.heightAnchor.constraintEqualToAnchor( mainContainer.heightAnchor, multiplier: 0.1).active = true
} }
So when the keyboard appears the bottom anchor constant of the scroll view changes so that the keyboard "top anchor" is the new bottom anchor.
With the constraints you have described there's no way for the layout engine to determine the content height of the scroll view. You should pin your bottom text field to the bottom of the scroll view. This way the scroll view's content size will resize up to the max y of all of the text fields. Here is some code you can put in a playground to see:
import UIKit
import XCPlayground
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
scrollView.backgroundColor = UIColor.whiteColor()
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.backgroundColor = UIColor.purpleColor()
let otherTextField = UITextField()
otherTextField.translatesAutoresizingMaskIntoConstraints = false
otherTextField.backgroundColor = UIColor.purpleColor()
let otherOtherTextField = UITextField()
otherOtherTextField.translatesAutoresizingMaskIntoConstraints = false
otherOtherTextField.backgroundColor = UIColor.purpleColor()
scrollView.addSubview(textField)
textField.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
textField.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
textField.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
scrollView.addSubview(otherTextField)
otherTextField.topAnchor.constraintEqualToAnchor(textField.bottomAnchor, constant: 60).active = true
otherTextField.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
otherTextField.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
scrollView.addSubview(otherOtherTextField)
otherOtherTextField.topAnchor.constraintEqualToAnchor(otherTextField.bottomAnchor, constant: 60).active = true
otherOtherTextField.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
otherOtherTextField.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
otherOtherTextField.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
scrollView.setNeedsLayout()
XCPlaygroundPage.currentPage.liveView = scrollView
This places three text fields in a scroll view with 60 points between the center and top and bottom. If you comment out:
otherOtherTextField.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
The scroll view in the assistant editor will not scroll, but with it it does.