Text won't show with constraints added - ios

So here is my current code for the viewdidload and the setup view func
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(bearImageView)
view.addSubview(descriptionText)
view.addSubview(startButton)
setupView()
}
#objc private func start() {
}
private func setupView() {
bearImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
bearImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
bearImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
bearImageView.heightAnchor.constraint(equalToConstant: 250).isActive = true
descriptionText.topAnchor.constraint(equalTo: bearImageView.bottomAnchor, constant: 10).isActive = true
descriptionText.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
descriptionText.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
startButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
startButton.topAnchor.constraint(equalTo: descriptionText.bottomAnchor, constant: 140).isActive = true
startButton.widthAnchor.constraint(equalToConstant: 80).isActive = true
startButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
Both the bearimage and button constraints work fine (minus flipping the phone horizontally but ill fix that later) however the text just refuses to show. The text are made programmatically for istance let descriptionText = UITextView = {...}() and etc. Any of you guys have an idea?

If you look closely you have missed the Height Constraint for your UITextView. If you're using a UILabel or UITextField they don't need a height constraint and can calculate their height based on it's inner contents but UITextView is not going to do that because it will start scrolling if the contents is more than it's height and that's why it can not set the height based on it's inner contents and it's height is zero by default.
add a HeightConstraint to your UITextView as well.
// This will fix your problem
descriptionText.heightAnchor.constraint(equalToConstant: 120).isActive = true

It's possible the image's intrinsic content size is so large that it is expanding such that there is no more space available for the descriptionText label. Try updating the content compression resistance priority of the label to required so it cannot be compressed by the image view.
Swift 3:
descriptionText.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
Swift 4:
descriptionText.setContentCompressionResistancePriority(.required, for: .vertical)

Related

How can I fix these constraints so the text appears to the right of the image in my UITableViewCell?

I am having issues with my constraints on my UITableViewCells and I can't seem to figure out how to fix these constraints that I've coded. I want the text to stretch across the cell and start to right of the image on the far left side. I just want the text centered in the cell if possible but I am unsure of how to accomplish this goal. As of right now, I have the width set to the height of the text but if you're able to help guide me so the text is adjacent to the image on the left side, that would be greatly appreciated. I have also attached a picture below of the current setup (which you will agree looks quite ugly)
Heres the code:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.addSubview(mainImageView)
self.addSubview(messageView)
mainImageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
mainImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
mainImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
mainImageView.widthAnchor.constraint(equalToConstant: 50).isActive = true
mainImageView.heightAnchor.constraint(equalToConstant: 50).isActive = true
messageView.leftAnchor.constraint(equalTo: self.rightAnchor).isActive = true
messageView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
messageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
messageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
messageView.widthAnchor.constraint(equalTo: self.heightAnchor).isActive = true
}
enter image description here
first you need to set
translatesAutoresizingMaskIntoConstraints = false
for each component before add constraints.
after that here you set imageview top,bottom & height,width constraints also.each will conflict with other.you have to use only one set of them.either top,bottom or height,width.
using top,bottom constraints is not recommended.it makes image stretchy sometimes.better using width height constraints and center your image to center Y.
mainImageView.translatesAutoresizingMaskIntoConstraints = false
mainImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor,constant:16).isActive = true
mainImageView.widthAnchor.constraint(equalToConstant: 50).isActive = true
mainImageView.heightAnchor.constraint(equalToConstant: 50).isActive = true
mainImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
messageView.translatesAutoresizingMaskIntoConstraints = false
messageView.leadingAnchor.constraint(equalTo: mainImageView.trailingAnchor, constant: 16).isActive = true
messageView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -16).isActive = true
messageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
you can center your text in messageview using textAlignment

White lines in ViewController on Screen Rotation

I am new to iOS development. I encountered the problem, when I rotate the screen on iPhone X emulator I got white stripes on the side of the screen as you see on the second picture.
I have already set background for ViewController and for TableView.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Colors.backGround
view.tintColor = Colors.backGround
It did not help. When the app starts from landscape mode the issue disappears.
Your blue view area has leading and trailing constraint to safe area.
Just make it to superview.
EDIT:
Here is code for same to achieve with swift code
//Creating tableview
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.backgroundColor = .lightGray
tableView.dataSource = self
self.view.addSubview(tableView)
//Setting layout of tableview
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
//Setting insets for respect safe area
tableView.contentInset = self.view.safeAreaInsets
Here are screenshots for same.
Vertical
Horizontal
If you created UITableView Programmatically
then follow the below steps
private let tableView = UITableView()
then
func setupView() {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
}
then
func setupConstraints() {
self.tableView.topAnchor.constraint(equalTo: (self.tableView.superview.safeAreaLayoutGuide.topAnchor), constant: 0).isActive = true
self.tableView.leadingAnchor.constraint(equalTo: (self.tableView.superview.leadingAnchor), constant: 0).isActive = true
self.tableView.trailingAnchor.constraint(equalTo: (self.tableView.superview.trailingAnchor), constant: 0).isActive = true
self.tableView.bottomAnchor.constraint(equalTo: (self.tableView.superview.safeAreaLayoutGuide.bottomAnchor), constant: 0).isActive = true
}
Change your leading and trailing (or left and right) constraints for tableView from safe area to superview and the table will fill the screen horizontally.
Alternatively, just set the background color of the white view to that of the table view. That will ensure your table view content is always visible because it will stay inside the safe area (I'm assuming the white view is self.view here):
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = tableView.backgroundColor
}

Height of the UITextView increases when using IQKeyboardManagers

I recently started to use IQKeyboardManager in my app that I am working on, it works really well except for a little problem. The height of my text view increases when the keyboard appears(Which makes the text view go up), I know this because I am printing the height of the text view each time I click on the text view. Here is the code of my text view:
// Setup text view
func setupTextView() {
// Placeholder text and color
startStoryTextView.textColor = .gray
startStoryTextView.text = "Type here"
startStoryTextView.backgroundColor = .red
// Add some padding to the text insde the text view
startStoryTextView.textContainerInset = UIEdgeInsets(top: 15, left: 10, bottom: 15, right: 10)
startStoryTextView.font = UIFont(name: "PatrickHand-Regular", size: 23)
startStoryTextView.layer.cornerRadius = 25
popUp.addSubview(startStoryTextView)
addTextViewConstraints()
}
// Add the constraints to the text view
func addTextViewConstraints() {
startStoryTextView.translatesAutoresizingMaskIntoConstraints = false
startStoryTextView.leadingAnchor.constraint(equalTo: popUp.leadingAnchor, constant: 3).isActive = true
startStoryTextView.trailingAnchor.constraint(equalTo: popUp.trailingAnchor, constant: -3).isActive = true
startStoryTextView.topAnchor.constraint(equalTo: popUp.topAnchor, constant: 3).isActive = true
//startStoryTextView.heightAnchor.constraint(equalToConstant: 589).isActive = true
startStoryTextView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -70).isActive = true
}
// Add constraints to the pop up view
func addPopUpConstraints() {
popUp.translatesAutoresizingMaskIntoConstraints = false
popUp.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
popUp.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 10).isActive = true
popUp.topAnchor.constraint(equalTo: view.topAnchor, constant: 200).isActive = true
popUp.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
Specifying the height of the text view solves this problem but, it will create another problem when the app is used on other devices with different resolutions.
// To print the height of the text view every time the user clicks on the text view
func textViewDidBeginEditing(_ textView: UITextView) {
print(startStoryTextView.frame.height)
}
Don't worry, It is IQKeyboardManager's feature, not an error.
You use IQKeyboardManager, because you want the textView go up, when textViewDidBeginEditing.
The source code is very clear.
When you activate IQKeyboardManager, in IQKeyboardManager.swift, you call override init() {, override init() { do registerAllNotifications ,registerAllNotifications do Registering for UITextField notification.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShowDng(_:)), name: UIKeyboardWillShow, object: nil)
// ...
keyboard is already showing. adjust position.
In method func optimizedAdjustPosition()(), the height changes
Your code is weird.
why startStoryTextView.bottomAnchor is related to view.safeAreaLayoutGuide.bottomAnchor.
startStoryTextView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -70).isActive = true
Since startStoryTextView.superView is popUp
popUp.addSubview(startStoryTextView)
I think it is code error. IQKeyboardManager unrelated.

How to account for different screen sizes when writing layout code programmatically

I'm creating the screen for a login screen, I first tried to build using the storyboard, but it got really confusing very fast. So I jumped to the code, the code I wrote is for an Image, Text, two text fields, and three buttons to show in a simple view similar to a stack view.
Here's an example of two different on the right is the iPhone SE and on the left is the iPhone XR.
The layout looks fine for the SE but really small for the XR. How do I account for the screen changes so that the UI looks the same on all devices?
Here's the code I used for adding the constraints programmatically:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Round the edges
Login.layer.cornerRadius = 4
Register.layer.cornerRadius = 4
logo.translatesAutoresizingMaskIntoConstraints = false
logo.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
logo.widthAnchor.constraint(equalToConstant: 200).isActive = true
logo.heightAnchor.constraint(equalToConstant: 80).isActive = true
logo.topAnchor.constraint(equalTo: view.topAnchor, constant: 90).isActive = true
logo.contentMode = .scaleAspectFit
letsloginTextField.translatesAutoresizingMaskIntoConstraints = false
letsloginTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
letsloginTextField.bottomAnchor.constraint(equalTo: logo.bottomAnchor, constant: 50).isActive = true
emailTextField.translatesAutoresizingMaskIntoConstraints = false
emailTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
emailTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
emailTextField.widthAnchor.constraint(equalToConstant: 180).isActive = true
emailTextField.heightAnchor.constraint(equalToConstant: 30).isActive = true
//emailTextField.bottomAnchor.constraint(equalTo: letsloginTextField.bottomAnchor, constant: 50).isActive = true
passwordTextField.translatesAutoresizingMaskIntoConstraints = false
passwordTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
passwordTextField.widthAnchor.constraint(equalToConstant: 180).isActive = true
passwordTextField.heightAnchor.constraint(equalToConstant: 30).isActive = true
passwordTextField.bottomAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 50).isActive = true
Login.translatesAutoresizingMaskIntoConstraints = false
Login.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
Login.widthAnchor.constraint(equalToConstant: 100).isActive = true
Login.heightAnchor.constraint(equalToConstant: 30).isActive = true
Login.bottomAnchor.constraint(equalTo: passwordTextField.bottomAnchor, constant: 60).isActive = true
Register.translatesAutoresizingMaskIntoConstraints = false
Register.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
Register.widthAnchor.constraint(equalToConstant: 100).isActive = true
Register.heightAnchor.constraint(equalToConstant: 30).isActive = true
Register.bottomAnchor.constraint(equalTo: Login.bottomAnchor, constant: 60).isActive = true
// set delegates
GIDSignIn.sharedInstance().uiDelegate = self
//GIDSignIn.sharedInstance().signIn()
}
You could set the width of the views relative to the screen width like to following:
let width = UIScreen.main.bounds.size.width * 0.3
emailTextField.widthAnchor.constraint(equalToConstant: width).isActive = true
and then you set a ratio for your views. for eg: the height is 1:2 the width
emailTextField.heightAnchor.constraint(equalToConstant: width * 0.5).isActive = true
Change the values according to your need.
I strongly suggest getting into XCode Interface Builder:
https://developer.apple.com/videos/developer-tools/interface-builder
Furthermore, you need to change your way of thinking how to setup an UI for a mobile Device.
For example: In your case this means instead of defining width constraints for the Login and Register Button - you may define leading and trailing constraints from the Button-border to the border of the UIViewController and perhaps just set a fixed height constraint for them. This will make the Buttons dynamically adapt to the Device.
The next suggestion would be to avoid layouting this elements within code. Interface Builder makes it really easy to define these layouts and you will get a lot of handy features for free, furthermore it also can handle more complex layouts. Your code will become unmanageable and hard to read/change if the UI will get more complex. Furthermore it will introduce a lot of Boilerplate code.
In this case you need to playing with screen size.
1. Get screen width
`let screenWidth = UIScreen.main.bounds.size.width
2. Set margin of button (left, right)
let margin = 60
Note : left margin = 30, right margin = 30 total Margin = 60, you can change margin as per your design requirements.
3. Set our button size
New code
Register.widthAnchor.constraint(equalToConstant:screenWidth - margin).isActive = true
Your old code
Register.widthAnchor.constraint(equalToConstant: 100).isActive = true
Note : This is only for portrait mode.

Swift iOS -How to set UIView's Height Anchor <= To A Label's Intrinsic Text Size? 'NSLayoutConstraint' is not convertible to 'Bool'

I have a programmatic view with a label inside of it that I'm pinning to the bottom of the navBar. There will be dynamic text inside of the label and I want the view the label is in to be the at least 64 pts or bigger if the height of text makes it smaller.
The intrinsic size of the text from this label sets the view at a noticeable height.
setViewAndLabel(dynamicText: "Unknown Error\nPlease try your request again\Error: 123")
However the intrinsic size of this text makes the height to small:
setViewAndLabel(dynamicText: "Message Deleted!")
The Message Deleted! should be more along the lines of:
I used some return keys to set it like that but I don't think that's the correct way to go because different messages will get generated:
setViewAndLabel(dynamicText: "\nMessage Deleted!\n")
I also tried:
if myView.heightAnchor.constraint(lessThanOrEqualToConstant: 64){
myView.heightAnchor.constraint(equalToConstant: 64).isActive = true
}
But I get the error:
'NSLayoutConstraint' is not convertible to 'Bool'
What's the best way to set the height for the view the label is in to a minimum height?
var myLabel: UILabel(){
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.white
label.font = UIFont(name: "Helvetica-Regular", size: 19)
label.numberOfLines = 0
label.sizeToFit()
label.textAlignment = .center
return label
}
let myView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated){
setViewAndLabel(dynamicText: //some text will get set here)
}
func setViewAndLabel(dynamicText: String){
view.addSubView(myView)
myView.backgroundColor = UIColor.red
myView.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
View.widthAnchor.constraint(equalTo: view.widthAnchor, constant: 0).isActive = true
myView.addSubView(myLabel)
myLabel.text = dynamicText
myLabel.topAnchor.constraint(equalTo: myView.topAnchor, constant: 0).isActive = true
myLabel.widthAnchor.constraint(equalTo: myView.widthAnchor, constant: 0).isActive = true
myView.bottomAnchor.constraint(equalTo: myLabel.bottomAnchor, constant: 0).isActive = true
//this if statement doesn't work
if myView.heightAnchor.constraint(lessThanOrEqualToConstant: 64){
viewForErrorLabel.heightAnchor.constraint(equalToConstant: 64).isActive = true
}
}
This is how you have to set up your constraints:
view.addSubview(myView)
myView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
myView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
myView.heightAnchor.constraint(greaterThanOrEqualToConstant: 64).isActive = true
myView.addSubview(myLabel)
myLabel.topAnchor.constraint(equalTo: myView.topAnchor).isActive = true
myLabel.leadingAnchor.constraint(equalTo: myView.leadingAnchor).isActive = true
myLabel.trailingAnchor.constraint(equalTo: myView.trailingAnchor).isActive = true
myLabel.bottomAnchor.constraint(equalTo: myView.bottomAnchor).isActive = true
You do not need to check the label's height at all. You can simply always create that height greater than or equal constraint for myView and its height will never be smaller than 64pt (or whatever value you set it to) - even if the label contains a very short text.

Resources