I know you use ignoresSafeArea() in SwiftUI to make some UI-element-frame dismiss the safe area. However, when using UIKit I don't know how to do it. I want to place a UILabel right below the actual screen, but I cannot see it because it is hidden behind the safe area.
import UIKit
class SignInViewController: UIViewController {
private let headline = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
addLabel()
view.backgroundColor = .black
}
func addLabel() {
headline.text = "SmashPass"
headline.textColor = UIColor.red
headline.frame = CGRect(x: 0 , y: 0 , width: 243, height: 29)
headline.textAlignment = .center
// alignment
headline.center.x = view.center.x
headline.center.y = view.frame.minY - 10
view.addSubview(headline)
}
}
Learn about how to use Auto-Layout...
Here is your code, with modifications to use Constraints and Auto-Layout to place the label at the bottom of the view:
class SignInViewController: UIViewController {
private let headline = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
addLabel()
view.backgroundColor = .black
}
func addLabel() {
headline.text = "SmashPass"
headline.textColor = UIColor.red
headline.textAlignment = .center
// -- use Auto-Layout!
// alignment
//headline.frame = CGRect(x: 0 , y: 0 , width: 243, height: 29)
//headline.center.x = view.center.x
//headline.center.y = view.frame.minY - 10
view.addSubview(headline)
headline.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// label uses full-width
headline.leadingAnchor.constraint(equalTo: view.leadingAnchor),
headline.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// constrain the label bottom to the view bottom
headline.bottomAnchor.constraint(equalTo: view.bottomAnchor),
// label height is 29-points
headline.heightAnchor.constraint(equalToConstant: 29.0),
])
}
}
Note: in general, we want to constrain elements with awareness of the Safe-Area...
Using that code, we'll get this on an iPhone 12 Pro (for example):
and, if we set headline.backgroundColor = .yellow so we can see the label's frame:
let longTitleLabel = UILabel()
longTitleLabel.text = "Profile"
//longTitleLabel.font = ................
longTitleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 31)
override func viewDidAppear(_ animated: Bool) {
let height: CGFloat = 25
let bounds = self.navigationController!.navigationBar.bounds
self.navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height + height)
}
I have this nav bar in my view controller and the text profile on it. Can I change the position in which it is located. For example constraint it to the left and top so it moves it down more.
Instead of giving frame to navigationBar give frame to your label and add it in NavBar like
let longTitleLabel = UILabel()
longTitleLabel.text = "Profile my boy hello jee wao"
longTitleLabel.textAlignment = .center
longTitleLabel.backgroundColor = .red
longTitleLabel.translatesAutoresizingMaskIntoConstraints = false
if let navigationBar = self.navigationController?.navigationBar {
navigationBar.addSubview(longTitleLabel)
longTitleLabel.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -20).isActive = true
longTitleLabel.leftAnchor.constraint(equalTo: navigationBar.leftAnchor, constant: 20).isActive = true
longTitleLabel.widthAnchor.constraint(equalToConstant: 100).isActive = true
longTitleLabel.heightAnchor.constraint(equalToConstant: navigationBar.bounds.maxY).isActive = true
}
Hopefully resolve your issue
I have a button that is text. I added a red background subLayer and I made the backgroundLayer's width and height bigger then the button text. I tried to center the background layer to the button using:
backgroundLayer.position = button.center
It's not centering. This is what I get:
I know I can set the background color and cornerRadius on the button directly but when I do it that way the red background hugs the text:
button.backgroundColor = UIColor.red
button.layer.cornerRadius = 10
I want the redbackground to be wider and taller then the text:
backgroundLayer.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width + 10, height: buttonTextSize.height + 5
I would Photoshop an example but I don't have Photshop in front of me at the moment. This is the closest I can find. This is a button from Vimeo. They aren't using text but the backgroundLayer is much wider and taller then the button image and the backgroundLayer's position is aligned with the button's midX and midY:
How do I get the position of the background subLayer to line up with the center of the button's text?
let button: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Next", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.contentHorizontalAlignment = .center
button.titleLabel?.font = UIFont.systemFont(ofSize: 23)
return button
}()
let backgroundLayer: CALayer = {
let layer = CALayer()
layer.backgroundColor = UIColor.red.cgColor
layer.cornerRadius = 10
return layer
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
view.addSubview(button)
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let buttonText = button.titleLabel?.text
let buttonTextSize = (buttonText! as NSString).size(withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 23.0)])
// I added 10 points to the backgroundLayer's width and 5 points to the backgroundLayer's height so its wider then the text
backgroundLayer.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width + 10, height: buttonTextSize.height + 5)
button.layer.insertSublayer(backgroundLayer, at: 0)
backgroundLayer.position = button.center
}
Here's a button that seems to look the way you want (of course you can adjust any parameters that don't suit your sensibilities):
This button is automatically red, corner-rounded, and considerably larger than its text (even when the button is positioned using auto layout).
Here's how it was achieved through a subclass:
class MyRedButton : UIButton {
override func layoutSubviews() {
super.layoutSubviews()
self.backgroundColor = .red
self.layer.cornerRadius = 10
}
override var intrinsicContentSize: CGSize {
var sz = super.intrinsicContentSize
sz.width += 30; sz.height += 30
return sz
}
}
Matt's upvoted answer is correct.
Two things he pointed out to me in the comments that I was initially doing wrong was.
I tried to set backgroundLayer.position = button.center. This is wrong because the button's center is based on the frame's center and not it's bounds center. I should've set the backgroundLayer.position to match the center of the button's bounds
I tried to set the backgroundLayer's position to the button's center in viewWillLayoutSubviews which he said the button's bounds weren't known yet so the backgroundLayer had no information to base it on. I was supposed to add the code to viewDidLayoutSubviews
Here's the code here:
// 1. add the code to viewDidLayoutSubviews
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let text = button.titleLabel?.text
let textSize = (text! as NSString).size(withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 23.0)])
backgroundLayer.frame = CGRect(x: 0, y: 0, width: textSize.width + 10, height: textSize.height + 5)
button.layer.insertSublayer(backgroundLayer, at: 0)
// 2. get the buttons bound's center by accessing it's midX and midY
let buttonMidX = button.bounds.midX
let buttonMidY = button.bounds.midY
let buttonBoundsCenter = CGPoint(x: buttonMidX, y: buttonMidY)
// 3. set the backgroundLayer's postion to the buttonBoundsCenter
backgroundLayer.position = buttonBoundsCenter
}
And it works:
I have the following view which contains a UILabel:
class MyView : UIView {
func viewDidLoad() {
self.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
bottomView = UIView(frame: CGRectMake(self.bounds.origin.x, self.bounds.origin.y + self.imageView!.bounds.size.width, self.bounds.size.width, self.bounds.size.height - self.imageView!.bounds.size.height))
// bottomView frame calculation is: (0.0, 355.0, 355.0, 130.0)
bottomView?.backgroundColor = UIColor.greenColor()
bottomView?.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView?.clipsToBounds = true
self.addSubview(self.bottomView!)
var descriptionRect: CGRect = CGRectInset(self.bottomView!.bounds, leftRightInset, 20/2)
let descriptionLabel = UILabel()
descriptionLabel.numberOfLines = 3
descriptionLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth
descriptionLabel.font = UIFont(name: MGFont.helvetica, size: 22)
descriptionLabel.textColor = UIColor.whiteColor()
descriptionLabel.textAlignment = NSTextAlignment.Left
descriptionLabel.backgroundColor = UIColor.blueColor()
var paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1.0
paragraphStyle.lineBreakMode = NSLineBreakMode.ByTruncatingTail
let attributes = [NSParagraphStyleAttributeName : paragraphStyle]
descriptionLabel.attributedText = NSAttributedString(string: previewCard.title, attributes:attributes)
bottomView?.addSubview(descriptionLabel)
descriptionLabel.bounds = descriptionRect
descriptionLabel.sizeToFit()
descriptionLabel.center = CGPointMake(bottomView!.bounds.width/2, bottomView!.bounds.height/2 - hotelNameLableHeight/2)
}
}
The height of the bottomView should always be fixed.
MyView is resized during runtime. This means that the green bottom view also increases in size.
Here is the result when the label has two and three lines:
It appears that the UILabel resizes its super view.
Note that I do not use AutoLayout.
override func layoutSubviews() {
super.layoutSubviews()
}
How can I prevent the UILabel from resizing its SuperView?
Edit: I also tried to comment bottomView?.clipsToBounds = true
Override setFrame: and setBounds: of the super view (subclass if they're plain UIViews), add breakpoints, and see the stack trace to find out what's causing them to resize.
There is no need to set the autoResizingMask on the label, just set the frame and it will get automatically centered. And of course you can set the insets for the UILabel accordingly. I've add below testing code FYI:
override func viewDidLayoutSubviews() {
addTestView(CGRectMake(0, 200, view.bounds.width, 50), labelStr: "I am a short testing label")
addTestView(CGRectMake(0, 260, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglong testing label")
addTestView(CGRectMake(0, 320, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglonglonglonglonglonglong testing label. Will be truncated")
}
func addTestView(frame:CGRect, labelStr: String){
let bottomView = UIView(frame:frame)
bottomView.backgroundColor = UIColor.greenColor()
bottomView.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView.clipsToBounds = true
view.addSubview(bottomView)
var label = UILabel(frame: bottomView.bounds)
label.textAlignment = NSTextAlignment.Left
label.numberOfLines = 0
label.text = labelStr
bottomView.addSubview(label)
}
How do I create a UILabel programmatically using Swift in Xcode 6?
I have started with a new "Single View Application" in Xcode 6 and selected Swift for this project. I have my files AppDelegate.swift and ViewController.swift and I'm not sure what to do from here.
Creating a UILabel programmatically in Swift 3+:
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
label.center = CGPoint(x: 160, y: 285)
label.textAlignment = .center
label.text = "I'm a test label"
self.view.addSubview(label)
}
Here is the correct code for Swift 3, with comments for instructional purposes:
override func viewDidLoad()
{
super.viewDidLoad()
// CGRectMake has been deprecated - and should be let, not var
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
// you will probably want to set the font (remember to use Dynamic Type!)
label.font = UIFont.preferredFont(forTextStyle: .footnote)
// and set the text color too - remember good contrast
label.textColor = .black
// may not be necessary (e.g., if the width & height match the superview)
// if you do need to center, CGPointMake has been deprecated, so use this
label.center = CGPoint(x: 160, y: 284)
// this changed in Swift 3 (much better, no?)
label.textAlignment = .center
label.text = "I am a test label"
self.view.addSubview(label)
}
Just to add onto the already great answers, you might want to add multiple labels in your project so doing all of this (setting size, style etc) will be a pain. To solve this, you can create a separate UILabel class.
import UIKit
class MyLabel: UILabel {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeLabel()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeLabel()
}
func initializeLabel() {
self.textAlignment = .left
self.font = UIFont(name: "Halvetica", size: 17)
self.textColor = UIColor.white
}
}
To use it, do the following
import UIKit
class ViewController: UIViewController {
var myLabel: MyLabel()
override func viewDidLoad() {
super.viewDidLoad()
myLabel = MyLabel(frame: CGRect(x: self.view.frame.size.width / 2, y: self.view.frame.size.height / 2, width: 100, height: 20))
self.view.addSubView(myLabel)
}
}
Swift 4.X and Xcode 10
let lbl = UILabel(frame: CGRect(x: 10, y: 50, width: 230, height: 21))
lbl.textAlignment = .center //For center alignment
lbl.text = "This is my label fdsjhfg sjdg dfgdfgdfjgdjfhg jdfjgdfgdf end..."
lbl.textColor = .white
lbl.backgroundColor = .lightGray//If required
lbl.font = UIFont.systemFont(ofSize: 17)
//To display multiple lines in label
lbl.numberOfLines = 0 //If you want to display only 2 lines replace 0(Zero) with 2.
lbl.lineBreakMode = .byWordWrapping //Word Wrap
// OR
lbl.lineBreakMode = .byCharWrapping //Charactor Wrap
lbl.sizeToFit()//If required
yourView.addSubview(lbl)
If you have multiple labels in your class use extension to add properties.
//Label 1
let lbl1 = UILabel(frame: CGRect(x: 10, y: 50, width: 230, height: 21))
lbl1.text = "This is my label fdsjhfg sjdg dfgdfgdfjgdjfhg jdfjgdfgdf end..."
lbl1.myLabel()//Call this function from extension to all your labels
view.addSubview(lbl1)
//Label 2
let lbl2 = UILabel(frame: CGRect(x: 10, y: 150, width: 230, height: 21))
lbl2.text = "This is my label fdsjhfg sjdg dfgdfgdfjgdjfhg jdfjgdfgdf end..."
lbl2.myLabel()//Call this function from extension to all your labels
view.addSubview(lbl2)
extension UILabel {
func myLabel() {
textAlignment = .center
textColor = .white
backgroundColor = .lightGray
font = UIFont.systemFont(ofSize: 17)
numberOfLines = 0
lineBreakMode = .byCharWrapping
sizeToFit()
}
}
Create UILabel view outside viewDidLoad class and then add that view to your main view in viewDidLoad method.
lazy var myLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "This is label view."
label.font = UIFont.systemFont(ofSize: 12)
return label
}()
And then add that view in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myLabel)
// Set its constraint to display it on screen
myLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
myLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
You can create a label using the code below. Updated.
let yourLabel: UILabel = UILabel()
yourLabel.frame = CGRect(x: 50, y: 150, width: 200, height: 21)
yourLabel.backgroundColor = UIColor.orange
yourLabel.textColor = UIColor.black
yourLabel.textAlignment = NSTextAlignment.center
yourLabel.text = "test label"
self.view.addSubview(yourLabel)
Another answer in Swift 3:
let myLabel = UILabel()
myLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myLabel.center = CGPoint(x: 0, y: 0)
myLabel.textAlignment = .center
myLabel.text = "myLabel!!!!!"
self.view.addSubview(myLabel)
Create label in swift 4
let label = UILabel(frame: CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: 50))
label.textAlignment = .center
label.text = "Hello this my label"
//To set the color
label.backgroundColor = UIColor.white
label.textColor = UIColor.black
//To set the font Dynamic
label.font = UIFont(name: "Helvetica-Regular", size: 20.0)
//To set the system font
label.font = UIFont.systemFont(ofSize: 20.0)
//To display multiple lines
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping //Wrap the word of label
label.lineBreakMode = .byCharWrapping //Wrap the charactor of label
label.sizeToFit()
self.view.addSubview(label)
An alternative using a closure to separate out the code into something a bit neater using Swift 4:
class theViewController: UIViewController {
/** Create the UILabel */
var theLabel: UILabel = {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.textColor = UIColor.white
label.textAlignment = .left
label.numberOfLines = 3
label.font = UIFont(name: "Helvetica-Bold", size: 22)
return label
}()
override func viewDidLoad() {
/** Add theLabel to the ViewControllers view */
view.addSubview(theLabel)
}
override func viewDidLayoutSubviews() {
/* Set the frame when the layout is changed */
theLabel.frame = CGRect(x: 0,
y: 0,
width: view.frame.width - 30,
height: 24)
}
}
As a note, attributes for theLabel can still be changed whenever using functions in the VC. You're just setting various defaults inside the closure and minimizing clutter in functions like viewDidLoad()
Swift 4.2 and Xcode 10. Somewhere in ViewController:
private lazy var debugInfoLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
yourView.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: suggestionView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: suggestionView.centerYAnchor, constant: -100),
label.widthAnchor.constraint(equalToConstant: 120),
label.heightAnchor.constraint(equalToConstant: 50)])
return label
}()
...
Using:
debugInfoLabel.text = debugInfo
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
label.center = CGPoint(x: 160, y: 285)
label.textAlignment = .center
label.text = "My label"
self.view.addSubview(label)
Try above code in ViewDidLoad
Swift 4.2 and Xcode 10
Initialize label before viewDidLoad.
lazy var topLeftLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "TopLeft"
return label
}()
In viewDidLoad add label to the view and apply constraints.
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(topLeftLabel)
topLeftLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
topLeftLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
}