I have a CollectionView which has fills the whole screen, has horizontal scrollDirection and is paging enabled. It is inside of a NavigationController with a hidden navigationBar. The CollectionViewCells have the height of the screen too.
What I would expect to happen:
Each cell fills the whole screen and when I swipe to left/right another cell appears and fills the whole screen.
What actually happens:
The cells are not filling the whole screen. There is a little space (approx. 20 pxl) between the top of the cells and the top border of the screen. Also the bottom of the cell (also approx. 20 pxl) is "under" the bottom border of the screen.
Also i get a warning:
The behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
So the cells height is correct as it seems, but the y-value is wrong.
What I already tried:
override shouldInvalidateLayoutForBoundsChange to return true.
As you can see here the blue border is the border of the collectionView and the red border is the border of the cell. The blue border is, as I would expect it, but I would expect the red border to be like the blue border.
Here is the code:
class LoginController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, LoginControllerDelegate, UIGestureRecognizerDelegate {
lazy var loginCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.dataSource = self
cv.delegate = self
cv.isPagingEnabled = true
cv.layer.borderWidth = 1.0
cv.layer.borderColor = UIColor.blue.cgColor
return cv
}()
let introCellId = "IntroCellId"
let loginCellId = "LoginCellId"
let pages: [Page] = {
let firstPage = Page(title: String,
message: String,
imageName: String)
let secondPage = Page(title: String,
message: String,
imageName: String)
let thirdPage = Page(title: String,
message: String,
imageName: String)
return [firstPage, secondPage, thirdPage]
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = true
view.addSubview(loginCollectionView)
registerCells()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pages.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == pages.count {
let loginCell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath) as! LoginCell
loginCell.loginControllerDelegate = self
loginCell.layer.borderColor = UIColor.red.cgColor
loginCell.layer.borderWidth = 2.0
return loginCell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: introCellId, for: indexPath) as! PageCell
let page = pages[indexPath.item]
cell.page = page
cell.layer.borderColor = UIColor.red.cgColor
cell.layer.borderWidth = 2.0
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.loginCollectionView.frame.width, height: self.loginCollectionView.frame.height)
}
}
PageCell:
class PageCell: UICollectionViewCell {
var page: Page? {
didSet {
guard let page = page
else {
return
}
imageView.image = UIImage(named: page.imageName)
let color = UIColor(white: 0.2, alpha: 1)
let attributedText = NSMutableAttributedString(string: page.title, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.medium), NSAttributedString.Key.foregroundColor: color])
attributedText.append(NSMutableAttributedString(string: "\n\n\(page.message)", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.medium), NSAttributedString.Key.foregroundColor: color]))
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let length = attributedText.string.count
attributedText.addAttributes([NSAttributedString.Key.paragraphStyle: paragraphStyle], range: NSRange(location: 0, length: length))
textView.attributedText = attributedText
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.backgroundColor = UIColor(displayP3Red: 139/255, green: 221/255, blue: 116/255, alpha: 1)
iv.clipsToBounds = true
return iv
}()
let textView: UITextView = {
let tv = UITextView()
tv.isEditable = false
tv.contentInset = UIEdgeInsets(top: 24, left: 0, bottom: 0, right: 0)
tv.textColor = UIColor(displayP3Red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
return tv
}()
func setupViews() {
addSubview(imageView)
addSubview(textView)
_ = imageView.anchor(topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: screenWidth, heightConstant: (screenHeight) / 2)
_ = textView.anchor(imageView.bottomAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: screenWidth, heightConstant: (screenHeight) / 2)
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been impremented")
}
}
LoginCell:
class LoginCell: UICollectionViewCell {
let logoImageView: UIImageView = {
let image = UIImage(named: "logo green")
let imageView = UIImageView(image: image)
return imageView
}()
let emailTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "E-Mail"
textField.layer.borderColor = UIColor.lightGray.cgColor
let border = CALayer()
border.frame = CGRect(x: 0, y: 40, width: UIScreen.main.bounds.width - 64, height: 2.0)
border.backgroundColor = UIColor(displayP3Red: 51/255, green: 51/255, blue: 51/255, alpha: 1).cgColor
textField.layer.addSublayer(border)
textField.keyboardType = .emailAddress
return textField
}()
let emailAlertLabel: UILabel = {
let label = UILabel()
label.text = "E-Mail-Adresse nicht gefunden"
label.textColor = .red
label.isHidden = true
return label
}()
let passwordTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Passwort"
textField.layer.borderColor = UIColor.lightGray.cgColor
let border = CALayer()
border.frame = CGRect(x: 0, y: 40, width: UIScreen.main.bounds.width - 64, height: 2.0)
border.backgroundColor = UIColor(displayP3Red: 51/255, green: 51/255, blue: 51/255, alpha: 1).cgColor
textField.layer.addSublayer(border)
textField.isSecureTextEntry = true
return textField
}()
let passwordAlertLabel: UILabel = {
let label = UILabel()
label.text = "Ungültiges Passwort"
label.textColor = .red
label.isHidden = true
return label
}()
lazy var forgotPasswordButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = .white
button.setTitle("Passwort vergessen?", for: .normal)
button.setTitleColor(UIColor(displayP3Red: 139/255, green: 221/255, blue: 116/255, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(handleForgotPassword), for: .touchUpInside)
button.contentHorizontalAlignment = .left
return button
}()
lazy var loginButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(displayP3Red: 139/255, green: 221/255, blue: 116/255, alpha: 1)
button.setTitle("Login", for: .normal)
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(checkUserData), for: .touchUpInside)
button.layer.cornerRadius = 25.0
return button
}()
weak var loginControllerDelegate: LoginControllerDelegate?
lazy var stayLoggedInSwitch: UISwitch = {
let loginSwitch = UISwitch(frame: CGRect(x: 150, y: 150, width: 0, height: 0))
loginSwitch.addTarget(self, action: #selector(LoginCell.handleStayLoggedInState(_:)), for: .valueChanged)
loginSwitch.setOn(false, animated: true)
return loginSwitch
}()
let stayLoggedInTextField: UITextField = {
let textField = UITextField()
textField.text = "Angemeldet bleiben"
textField.textColor = UIColor(displayP3Red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
textField.isUserInteractionEnabled = false
return textField
}()
let registerLabel: UILabel = {
let label = UILabel()
label.text = "Sie haben noch keinen Account?"
label.textColor = .lightGray
label.backgroundColor = .white
label.font = label.font.withSize(13)
return label
}()
lazy var registerButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = .white
button.setTitle("Registrieren", for: .normal)
button.setTitleColor(UIColor(displayP3Red: 139/255, green: 221/255, blue: 116/255, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(handleRegister), for: .touchUpInside)
button.contentHorizontalAlignment = .left
button.titleLabel?.font = button.titleLabel?.font.withSize(13)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func setupViews() {
addSubview(logoImageView)
addSubview(emailTextField)
addSubview(emailAlertLabel)
addSubview(passwordTextField)
addSubview(passwordAlertLabel)
addSubview(forgotPasswordButton)
addSubview(loginButton)
addSubview(stayLoggedInSwitch)
addSubview(stayLoggedInTextField)
addSubview(registerLabel)
addSubview(registerButton)
_ = logoImageView.anchor(centerYAnchor, left: nil, bottom: nil, right: nil, topConstant: -230, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 160, heightConstant: 160)
logoImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
_ = emailTextField.anchor(logoImageView.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 35, leftConstant: 32, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 50)
_ = emailAlertLabel.anchor(emailTextField.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 32, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 20)
_ = passwordTextField.anchor(emailAlertLabel.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 32, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 50)
_ = passwordAlertLabel.anchor(passwordTextField.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 32, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 20)
_ = forgotPasswordButton.anchor(passwordAlertLabel.bottomAnchor, left: leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 32, bottomConstant: 0, rightConstant: 0, widthConstant: 200, heightConstant: 25)
_ = loginButton.anchor(forgotPasswordButton.bottomAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, topConstant: 4, leftConstant: 32, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 50)
_ = stayLoggedInSwitch.anchor(loginButton.bottomAnchor, left: leftAnchor, bottom: nil, right: nil, topConstant: 16, leftConstant: 32, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 50)
_ = stayLoggedInTextField.anchor(loginButton.bottomAnchor, left: stayLoggedInSwitch.rightAnchor, bottom: nil, right: rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 0, rightConstant: 32, widthConstant: 0, heightConstant: 32)
_ = registerLabel.anchor(nil, left: leftAnchor, bottom: bottomAnchor, right: nil, topConstant: 0, leftConstant: 32, bottomConstant: 32, rightConstant: 0, widthConstant: 200, heightConstant: 25)
_ = registerButton.anchor(nil, left: registerLabel.rightAnchor, bottom: bottomAnchor, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 32, rightConstant: 32, widthConstant: 0, heightConstant: 25)
emailTextField.addTarget(self, action: #selector(underlineTextFieldColor(sender:)), for: .editingDidBegin)
emailTextField.addTarget(self, action: #selector(underlineTextFieldDark(sender:)), for: .editingDidEnd)
passwordTextField.addTarget(self, action: #selector(underlineTextFieldColor(sender:)), for: .editingDidBegin)
passwordTextField.addTarget(self, action: #selector(underlineTextFieldDark(sender:)), for: .editingDidEnd)
}
#objc func underlineTextFieldDark(sender: UITextField) {
sender.layer.sublayers![0].backgroundColor = UIColor(displayP3Red: 51/255, green: 51/255, blue: 51/255, alpha: 1).cgColor
}
#objc func underlineTextFieldColor(sender: UITextField) {
sender.layer.sublayers![0].backgroundColor = UIColor(displayP3Red: 139/255, green: 221/255, blue: 116/255, alpha: 1).cgColor
}
#objc func handleLogin() {
loginControllerDelegate?.finishLoggingIn()
}
#objc func handleStayLoggedInState(_ sender: UISwitch) {
if (sender.isOn == true) {
UserDefaults.standard.setIsLoggedIn(value: true)
}
else {
UserDefaults.standard.setIsLoggedIn(value: false)
}
}
#objc func handleForgotPassword() {
loginControllerDelegate?.finishLoggingIn()
}
#objc func handleRegister() {
loginControllerDelegate?.finishLoggingIn()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The Anchor method:
extension UIView {
func anchor(_ top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) -> [NSLayoutConstraint] {
translatesAutoresizingMaskIntoConstraints = false
var anchors = [NSLayoutConstraint]()
if let top = top {
anchors.append(topAnchor.constraint(equalTo: top, constant: topConstant))
}
if let left = left {
anchors.append(leftAnchor.constraint(equalTo: left, constant: leftConstant))
}
if let bottom = bottom {
anchors.append(bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant))
}
if let right = right {
anchors.append(rightAnchor.constraint(equalTo: right, constant: -rightConstant))
}
if widthConstant > 0 {
anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
}
if heightConstant > 0 {
anchors.append(heightAnchor.constraint(equalToConstant: heightConstant))
}
anchors.forEach({$0.isActive = true})
return anchors
}
}
The collection view automatically set to the whole view. The contents of the collectionView is able to adjust the insects automatically if you do not set any behavior. At this case set automatic adjustment false to get the full-screen view. The top and bottom of the screen have a safe area for adjusting view with the notch.
Try this
collectionView?.contentInsetAdjustmentBehavior = .never
Hope this will fix this issue.
Related
Once my UIButton is pressed, I want to change the text of my UILabels. Right now when the button is pressed it transitions to a new ViewController with the same background and same theme, just with different text. I figure it is not the best approach. I cannot access my UILables outside of my function setUpView(). What is the best approach to do this.
#objc func buttonTapped(_ sender: UIButton){
//this is where I will change my text. myLabel.text = "new text"
let modalViewController = PageTwoViewController()
modalViewController.modalPresentationStyle = .overCurrentContext
present(modalViewController, animated: false)
}
func setUpView(){
let headerView = UIView()
headerView.backgroundColor = UIColor.rgb(red: 235, green: 248, blue: 242)
view.addSubview(headerView)
headerView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 150, paddingLeft: 20, paddingBottom: 150, paddingRight: 20, width: 0, height: 0)
let myLabel = UILabel()
myLabel.text = "Rate your xxxxx"
myLabel.textColor = UIColor.rgb(red: 0, green: 48, blue: 51)
myLabel.textAlignment = .left
myLabel.numberOfLines = 0
headerView.addSubview(myLabel)
myLabel.font = .systemFont(ofSize: 32)
myLabel.anchor(top: headerView.topAnchor, left: headerView.leftAnchor, bottom: nil, right: headerView.rightAnchor, paddingTop: 150, paddingLeft: 30, paddingBottom: 0, paddingRight: 40, width: 0, height: 0)
let steps = UILabel()
steps.text = "1 of 3"
steps.textColor = UIColor.rgb(red: 0, green: 48, blue: 51)
headerView.addSubview(steps)
steps.font = .systemFont(ofSize: 14)
headerView.addSubview(steps)
steps.anchor(top: nil, left: headerView.leftAnchor, bottom: myLabel.topAnchor, right: nil, paddingTop: 0, paddingLeft: 30, paddingBottom: 10, paddingRight: 0, width: 0, height: 0)
let button = UIButton(type: .system)
button.setTitle("Next", for: .normal)
button.layer.cornerRadius = 30
button.backgroundColor = UIColor.white
button.setTitleColor(UIColor.rgb(red: 0, green: 48, blue: 51), for: .normal)
button.layer.borderWidth = 1.7
button.layer.borderColor = UIColor.black.cgColor
button.titleLabel?.font = UIFont.systemFont(ofSize: 20)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
headerView.addSubview(button)
button.anchor(top: nil, left: headerView.leftAnchor, bottom: headerView.bottomAnchor, right: headerView.rightAnchor, paddingTop: 0, paddingLeft: 25, paddingBottom: 30, paddingRight: 25, width: 0, height: 60)
}
override func viewDidLoad() {
setUpView()
super.viewDidLoad()
}
You have to declare the variables globally and then change the text.
class TestViewController: UIViewController {
private var myButton : UIButton = {
let button = UIButton()
button.backgroundColor = .red
return button
}()
private var myLabel: UILabel = {
let label = UILabel()
return label
}()
func setupView() {
myButton.setTitle("My Button", .normal) //You can do it like this
myLabel.text = "This is my text"
}
}
You can declare your labels globally in your view controller and then you can use any where in view controller as follow:
let myLabel: UILabel = {
let label = UILabel()
return label
}()
I'm building a view programmatically where a blue button is supposed to be laid out in the center of the screen under a user image, but it's getting constrained to the top left corner every time. I have self.translatesAutoresizingMaskIntoConstraints set to false in the init method of this view. Here is my code where I restrain this button:
addSubview(continueMessagingButton)
continueMessagingButton.anchor(top: currentUserImage.bottomAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, padding: .init(top: 32, left: 48, bottom: 0, right: 48), size: .init(width: 0, height: 60))
continueMessagingButton.layer.cornerRadius = 30
Here is an image of what's happening:
Please help thank you!
full code:
import UIKit
import FirebaseCore
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import FirebaseAnalytics
class MatchView: UIView {
var userId: String! {
didSet {
API.User.observeCurrentUser { (user) in
self.currentUserImage.sd_setImage(with: URL(string:
user.profileImages!.first!))
self.currentUserImage.alpha = 1
}
API.User.observeUsers(withId: userId) { (user) in
self.otherUserImage.sd_setImage(with: URL(string:
user.profileImages!.first!))
self.otherUserImage.alpha = 1
}
}
}
let partyPopperImage: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName:
"party-popper-emoji"))
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
return imageView
}()
var username: String! {
didSet {
descriptionLabel.text = "Congratulations!\n\(username!) is
interested in you!"
}
}
let descriptionLabel: UILabel = {
let label = UILabel()
label.text = ""
label.lineBreakMode = .byWordWrapping
label.textAlignment = .center
label.textColor = #colorLiteral(red: 0.08732911403, green:
0.7221731267, blue: 1, alpha: 1)
label.font = UIFont(name: "Avenir-Medium", size: 19)
label.numberOfLines = 0
return label
}()
let currentUserImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.borderWidth = 2
imageView.layer.borderColor = #colorLiteral(red: 0.08732911403,
green: 0.7221731267, blue: 1, alpha: 1)
imageView.alpha = 0
return imageView
}()
let otherUserImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.borderWidth = 2
imageView.layer.borderColor = #colorLiteral(red: 0.08732911403,
green: 0.7221731267, blue: 1, alpha: 1)
imageView.alpha = 0
return imageView
}()
let continueMessagingButton: UIButton = {
let button = GlympsGradientButton(type: .system)
button.setTitle("CONTINUE MESSAGING", for: .normal)
button.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1,
alpha: 1), for: .normal)
button.backgroundColor = #colorLiteral(red: 0.08732911403, green: 0.7221731267, blue: 1, alpha: 1)
button.clipsToBounds = true
return button
}()
let messageLaterButton: UIButton = {
let button = GlympsGradientBorderButton(type: .system)
button.setTitle("Message Later", for: .normal)
button.setTitleColor(#colorLiteral(red: 0.08732911403, green:
0.7221731267, blue: 1, alpha: 1), for: .normal)
button.clipsToBounds = true
button.backgroundColor = .clear
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
continueMessagingButton.translatesAutoresizingMaskIntoConstraints =
true
setupBlurView()
setupLayout()
//setupAnimations()
let tap = UIGestureRecognizer(target: self, action:
#selector(handleDismiss))
self.addGestureRecognizer(tap)
}
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style:
.light))
func setupAnimations() {
let angle = 30 * CGFloat.pi / 180
currentUserImage.transform = CGAffineTransform(rotationAngle: -
angle).concatenating(CGAffineTransform(translationX: 200, y: 0))
otherUserImage.transform = CGAffineTransform(rotationAngle:
angle).concatenating(CGAffineTransform(translationX: -200, y: 0))
continueMessagingButton.transform = CGAffineTransform(translationX:
-500, y: 0)
messageLaterButton.transform = CGAffineTransform(translationX: 500,
y: 0)
UIView.animateKeyframes(withDuration: 1.3, delay: 0, options:
.calculationModeCubic, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration:
0.45, animations: {
self.currentUserImage.transform =
CGAffineTransform(rotationAngle: -angle)
self.otherUserImage.transform =
CGAffineTransform(rotationAngle: angle)
})
UIView.addKeyframe(withRelativeStartTime: 0.8,
relativeDuration: 0.5, animations: {
self.currentUserImage.transform = .identity
self.otherUserImage.transform = .identity
})
}) { (_) in
}
UIView.animate(withDuration: 0.75, delay: 0.6 * 1.3,
usingSpringWithDamping: 0.5, initialSpringVelocity: 0.1, options:
.curveEaseOut, animations: {
self.continueMessagingButton.transform = .identity
self.messageLaterButton.transform = .identity
})
}
func setupLayout() {
addSubview(partyPopperImage)
addSubview(descriptionLabel)
addSubview(currentUserImage)
addSubview(otherUserImage)
addSubview(continueMessagingButton)
//addSubview(messageLaterButton)
partyPopperImage.anchor(top: nil, leading: nil, bottom:
descriptionLabel.topAnchor, trailing: nil, padding: .init(top: 0, left:
0, bottom: 16, right: 0), size: .init(width: 150, height: 150))
partyPopperImage.centerXAnchor.constraint(equalTo:
self.centerXAnchor).isActive = true
descriptionLabel.anchor(top: nil, leading: self.leadingAnchor,
bottom: currentUserImage.topAnchor, trailing: trailingAnchor, padding:
.init(top: 0, left: 0, bottom: 32, right: 0), size: .init(width: 0,
height: 80))
currentUserImage.anchor(top: nil, leading: nil, bottom: nil,
trailing: centerXAnchor, padding: .init(top: 0, left: 0, bottom: 0,
right: 16), size: .init(width: 140, height: 140))
currentUserImage.layer.cornerRadius = 70
currentUserImage.centerYAnchor.constraint(equalTo:
centerYAnchor).isActive = true
otherUserImage.anchor(top: nil, leading: centerXAnchor, bottom:
nil, trailing: nil, padding: .init(top: 0, left: 16, bottom: 0, right:
0), size: .init(width: 140, height: 140))
otherUserImage.layer.cornerRadius = 70
otherUserImage.centerYAnchor.constraint(equalTo:
centerYAnchor).isActive = true
continueMessagingButton.anchor(top: currentUserImage.bottomAnchor,
leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, padding:
.init(top: 32, left: 48, bottom: 0, right: 48), size: .init(width: 0,
height: 60))
continueMessagingButton.layer.cornerRadius = 30
// messageLaterButton.anchor(top:
continueMessagingButton.bottomAnchor, leading:
continueMessagingButton.leadingAnchor, bottom: nil, trailing:
continueMessagingButton.trailingAnchor, padding: .init(top: 16, left:
0, bottom: 0, right: 0), size: .init(width: 0, height: 60))
// messageLaterButton.layer.cornerRadius = 30
self.layoutIfNeeded()
}
func setupBlurView() {
addSubview(visualEffectView)
visualEffectView.fillSuperview()
visualEffectView.alpha = 0
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping:
1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.visualEffectView.alpha = 1
}) { (_) in
}
}
#objc func handleDismiss() {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping:
1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.alpha = 0
}) { (_) in
self.removeFromSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I've figured out the issue. For my gradient colors I had:
let leftColor = UIColor.blue
let rightColor = UIColor.green
gradientLayer.colors = [leftColor, rightColor]
Once I added .cgColor to the ends of these, it worked:
gradientLayer.colors = [leftColor.cgColor, rightColor.cgColor]
Super minor, but this fixed the gradient!
I also needed to change the frame from
self.frame
to
gradientLayer.frame
Also minor, but this fixed the button location.
Can someone tell my why this code does not autosize the text in the descLabel? I tried to set the numberOfLines to 0 and I set a lineBreakMode but this pretty much does nothing to solve my problem. Is this approach not possible in a ViewController or do I do something completely wrong?
class SingleEventViewController: UIViewController {
var thisEvent: Event
var eventDescription: String?
let descLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 16)
label.text = "Beschreibung"
label.textColor = .black
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
let participateButton: UIButton = {
let button = UIButton()
button.backgroundColor = CalendarSettings.Colors.buttonBG
button.setTitle("Teilnehmen", for: .normal)
button.setTitleColor(CalendarSettings.Colors.darkRed, for: .normal)
return button
}()
//MARK: - Init & View Loading
init(event: Event) {
thisEvent = event
super.init(nibName: nil, bundle: nil)
setupDefaultValues()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
applyDefaultValues()
setupViews()
confBounds()
}
//MARK: - Setup
func setupDefaultValues() {
eventDescription = thisEvent.eventDescription
}
func applyDefaultValues() {
descLabel.text = eventDescription
}
func setupViews() {
view.addSubview(descLabel)
view.addSubview(participateButton)
let tabbarHeight = self.tabBarController?.tabBar.frame.height ?? 0
descLabel.anchor(top: titleLabel.bottomAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 5, paddingLeft: 10, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
participateButton.anchor(top: nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: tabbarHeight, paddingRight: 0, width: 0, height: 50)
}
To make it autoresize you must give it a left/leading and right/trailing constraints , or a fixed width
descLabel.anchor(top: titleLabel.bottomAnchor, left: view.leftAnchor, bottom: nil, rightview.rightAnchor, paddingTop: 5, paddingLeft: 10, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
If it is the font size you are trying to change so that it fits in the label then try adjustFontSizeToWidth, but if it is the label you wish to resize try sizeToFit().
I was searching this for a time but can't figure out how to implement the solutions I found.
Below post is defining what I really want and also It has a solution but in objective-c. I try to implement that solution but text started not to shown after that implementation.
UITextView bottom shadow on text
class AggrementView: UIView, UITextViewDelegate {
let acceptBtn = RippleButton()
let kvkkTextView = UITextView()
private let containerView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setupConstraints()
}
public convenience init(text: String, imageName: String){
self.init()
}
public convenience init(text: String, imageName: String, senderColor: UIColor){
self.init()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI(){
self.backgroundColor = .clear
acceptBtn.translatesAutoresizingMaskIntoConstraints = false
//acceptBtn.backgroundColor = UIColor(red:0.40, green:0.69, blue:0.07, alpha:1.0)
acceptBtn.backgroundColor = UIColor.gray
acceptBtn.layer.cornerRadius = 6.0
acceptBtn.setTitle("Onaylıyorum", for: UIControlState.normal)
acceptBtn.titleLabel?.font = UIFont(name: "Corbert-Regular", size: 20)!
acceptBtn.setTitleColor(UIColor.flatWhite, for: UIControlState.normal)
//acceptBtn.setAllSideShadow(shadowShowSize: 8.0)
acceptBtn.accessibilityIdentifier = "acceptBtn"
acceptBtn.isEnabled = false
acceptBtn.setTitleColor(UIColor.lightGray, for: .disabled)
kvkkTextView.font = UIFont(name: "Corbert-Regular", size: 15)!
kvkkTextView.setContentOffset(CGPoint.zero, animated: false)
kvkkTextView.layer.cornerRadius = 6.0
kvkkTextView.backgroundColor = .clear
kvkkTextView.layer.borderColor = UIColor.flatGray.cgColor
kvkkTextView.textColor = UIColor.flatWhite
kvkkTextView.delegate = self
kvkkTextView.isEditable = false
containerView.backgroundColor = .clear
containerView.layer.cornerRadius = 6.0
self.addSubview(containerView)
containerView.addSubview(acceptBtn)
containerView.addSubview(kvkkTextView)
}
private func setupConstraints(){
containerView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 90, leftConstant: 10, bottomConstant: 20, rightConstant: 10, widthConstant: 0, heightConstant: 0)
kvkkTextView.anchor(self.containerView.topAnchor, left: self.containerView.leftAnchor, bottom: self.acceptBtn.topAnchor, right: self.containerView.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
acceptBtn.anchor(nil, left: self.containerView.leftAnchor, bottom: self.containerView.bottomAnchor, right: self.containerView.rightAnchor, topConstant: 0, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 60)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.size.height) {
print( "View scrolled to the bottom" )
UIView.animate(withDuration: 0.5) {
self.acceptBtn.backgroundColor = UIColor(red:0.40, green:0.69, blue:0.07, alpha:1.0)
self.acceptBtn.isEnabled = true
}
}
let color = UIColor.lightGray
guard
let verticalIndicator = scrollView.subviews.last as? UIImageView,
verticalIndicator.backgroundColor != color,
verticalIndicator.image?.renderingMode != .alwaysTemplate
else { return }
verticalIndicator.layer.masksToBounds = true
verticalIndicator.layer.cornerRadius = verticalIndicator.frame.width / 2
verticalIndicator.backgroundColor = color
verticalIndicator.image = verticalIndicator.image?.withRenderingMode(.alwaysTemplate)
verticalIndicator.tintColor = .clear
}
Picture ref: #user2213271 in UITextView bottom shadow on text post
Here is the gradientCode I tried:
func applyShadow(){
var layerWidth: CGFloat = 8.0
var gl1 = CAGradientLayer()
var col1 = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0).cgColor
var col2 = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0).cgColor
gl1.colors = [col2, col1, col1, col2]
gl1.locations = [0.0, 0.0, 0.85, 1.0]
//underTextView - this is my UIView
gl1.frame = CGRect(x: 0, y: 0, width: underTextView.frame.width - layerWidth, height: underTextView.frame.height)
//layer for scrollIndicator - it must be visible always good
var gl2 = CAGradientLayer()
gl2.colors = [col1, col1]
gl2.locations = [0.0, 1.0]
gl2.frame = CGRect(x: underTextView.frame.width - layerWidth, y: 0, width: layerWidth, height: underTextView.frame.height)
//create main layer
var gl = CAGradientLayer()
gl.addSublayer(gl1)
gl.addSublayer(gl2)
//add to mask of UIView
underTextView.layer.mask = gl
}
It seems you forgot to add kvkkTextView.translatesAutoresizingMaskIntoConstraints = false before set kvkkTextView's anchor. So your kvkkTextView can't get its frame from constraints.
I've looked at almost every stackoverflow solution and for some odd reason my button will not round the corners. Can someone check and see what im doing wrong?
let goToMapsButton = UIButton(type: .custom)
scrollView.addSubview(goToMapsButton)
_ = goToMapsButton.anchor(map.bottomAnchor, left: nil, bottom: seperator.topAnchor, right: self.view.rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 16, rightConstant: 16, widthConstant: 50, heightConstant: 50)
goToMapsButton.backgroundColor = .green
goToMapsButton.layer.cornerRadius = 0.5 * goToMapsButton.bounds.size.width
goToMapsButton.clipsToBounds = true
goToMapsButton.layer.masksToBounds = true
Btw, Im doing this all in the viewDidLoad section of the view controller, if that info makes a difference.
Here is the full viewDidLoadClass for reference:` override func viewDidLoad() {
super.viewDidLoad()
let map = MKMapView()
let view1 = UIView()
view1.backgroundColor = .red
let storeAddress = UILabel()
storeAddress.text = "318 Atwood Avenue"
storeAddress.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)
let storeCity = UILabel()
storeCity.text = "Rainy River"
storeCity.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)
let seperator = UIView()
seperator.backgroundColor = .lightGray
let goToMapsButton = UIButton(type: .custom)
scrollView.addSubview(map)
scrollView.addSubview(view1)
scrollView.addSubview(storeAddress)
scrollView.addSubview(storeCity)
scrollView.addSubview(goToMapsButton)
scrollView.addSubview(seperator)
map.anchorToTop(scrollView.topAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor)
map.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.6).isActive = true
_ = storeAddress.anchor(map.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: nil, topConstant: 16, leftConstant: 16, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
_ = storeCity.anchor(storeAddress.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: nil, topConstant: 8, leftConstant: 16, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
_ = goToMapsButton.anchor(map.bottomAnchor, left: nil, bottom: nil, right: self.view.rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 16, rightConstant: 16, widthConstant: 50, heightConstant: 50)
goToMapsButton.backgroundColor = .green
print(goToMapsButton.frame.width)
goToMapsButton.layer.cornerRadius = 0.25 * goToMapsButton.frame.width
goToMapsButton.clipsToBounds = true
goToMapsButton.layer.masksToBounds = true
_ = seperator.anchor(storeCity.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor, topConstant: 8, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 1)
view1.anchorToTop(map.bottomAnchor, left: self.view.leftAnchor, bottom: scrollView.bottomAnchor, right: self.view.rightAnchor)
view1.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.8).isActive = true
}`
Move this code in viewWillLayoutSubviews:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
goToMapsButton.layer.cornerRadius = 0.25 * goToMapsButton.frame.width
}
Or create your custom class for button with rounded corners:
class RoundedButton: UIButton {
#IBInspectable var cornerRadius: CGFloat = 0
override func layoutSubviews() {
super.layoutSubviews()
clipsToBounds = true
layer.cornerRadius = cornerRadius
}
}
I face the same issue today, I'm using Anchor too. Well it looks like a one line stuff to me, never think it would takes that much of code.
The difficult is that we cannot get the frame.height or width in UIButton property closure because autolayout has not calculate the size at that time. I do a test to apply the purely round corner in viewDidLayoutSubviews.
And this is what it is looks like, although the declaration is separated for those UIButtons. I really don't like this way, I want to put all button declaration code in the same place, like a closure. However I don't find any other way to do it in internet.
let b1 = UIButton()
let b2 = UIButton()
let b3 = UIButton()
let b4 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
configureLayout()
}
private func configureLayout() {
// disable large title
navigationItem.largeTitleDisplayMode = .never
let topLabel = UILabel()
topLabel.text = "Import your music"
topLabel.font = .systemFont(ofSize: 30, weight: .heavy)
topLabel.numberOfLines = 0
topLabel.textColor = .black
topLabel.textAlignment = .center
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.axis = .vertical
stack.spacing = 40
stack.addArrangedSubview(topLabel)
b1.setTitle("Local drive", for: .normal)
b2.setTitle("Google", for: .normal)
b3.setTitle("OneNote", for: .normal)
b4.setTitle("DropBox", for: .normal)
b1.backgroundColor = .myBlue
b2.backgroundColor = .myGreen
b3.backgroundColor = .systemPink
b4.backgroundColor = .myPuple
b1.tag = 1
b2.tag = 2
b3.tag = 3
b4.tag = 4
[b1, b2, b3, b4].forEach { b in
b.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.gray, for: .highlighted)
stack.addArrangedSubview(b)
b.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}
view.addSubview(stack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
stack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
stack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
stack.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.75)
])
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
[b1, b2, b3, b4].forEach { b in
b.layer.cornerRadius = b1.frame.height / 2
b.layer.cornerCurve = .continuous
}
}
Give your button a frame. like that
goToMapsButton.frame = CGRect(x: xposition, y:yposition, width: widthyouwant, height: heightyouwant)
as currently your size of button is zero 0*0.5 = zero thats why its not applying any radius.
give it frame and it will work...
UIButton might have a background UIImage with rounded corners. It allowes you to set a background UIImage for each UIControlState of your UIButton.
open class UIButton : UIControl, NSCoding {
open func setBackgroundImage(_ image: UIImage?, for state: UIControlState)
}
If your UIButton's size is determined at runtime and the radius is fixed - you can use a resizable image:
open class UIImage : NSObject, NSSecureCoding {
open func resizableImage(withCapInsets capInsets: UIEdgeInsets) -> UIImage
}
On the gif below I use UIImage with size = CGSize(width: 7, height: 7), corner radius = 3 and cap insets = UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3)