I have added one label in my nib file, then its required to have top-left alignment for that lable. As I am providing text at runtime so its not sure that how much lines the
Swift 2.0: : Using UILabel Extension
Make constant enum values in a empty Swift file.
// AppRef.swift
import UIKit
import Foundation
enum UILabelTextPositions : String {
case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"
}
Using UILabel Extension:
Make a empty Swift class and name it. Add the following.
// AppExtensions.swift
import Foundation
import UIKit
extension UILabel{
func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel
{
let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0)
switch positionIdentifier
{
case "VerticalAlignmentTop":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height)
break;
case "VerticalAlignmentMiddle":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
rect.size.width, rect.size.height);
break;
case "VerticalAlignmentBottom":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height);
break;
default:
sampleLabel!.frame = bounds;
break;
}
return sampleLabel!
}
}
Usage :
myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
I found another solution for the same problem. I used UITextView
instead of UILabel
and switched editable()
function to false
.
I found a solution using AutoLayout in StoryBoard.
1) Set no of lines to 0 and text alignment to Left.
2) Set height constraint.
3) The height Constraint should be in Relation - Less Than or Equal
4)
override func viewWillLayoutSubviews() {
sampleLabel.sizeToFit()
}
I got the result as follows :
Building on top of totiG's awesome answer, I have created an IBDesignable class that makes it extremely easy to customize a UILabel's vertical alignment right from the StoryBoard. Just make sure that you set your UILabel's class to 'VerticalAlignLabel' from the StoryBoard identity inspector. If the vertical alignment doesn't take effect, go to Editor->Refresh All Views which should do the trick.
How it works: Once you set your UILabel's class correctly, the storyboard should show you an input field that takes an integer (alignment code).
Update: I've added support for centered labels ~Sev
Enter 0 for Top Alignment
Enter 1 for Middle Alignment
Enter 2 for Bottom Alignment
@IBDesignable class VerticalAlignLabel: UILabel {
@IBInspectable var alignmentCode: Int = 0 {
didSet {
applyAlignmentCode()
}
}
func applyAlignmentCode() {
switch alignmentCode {
case 0:
verticalAlignment = .top
case 1:
verticalAlignment = .topcenter
case 2:
verticalAlignment = .middle
case 3:
verticalAlignment = .bottom
default:
break
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.applyAlignmentCode()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.applyAlignmentCode()
}
enum VerticalAlignment {
case top
case topcenter
case middle
case bottom
}
var verticalAlignment : VerticalAlignment = .top {
didSet {
setNeedsDisplay()
}
}
override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
if #available(iOS 9.0, *) {
if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
switch verticalAlignment {
case .top:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .topcenter:
return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
} else {
switch verticalAlignment {
case .top:
return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .topcenter:
return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
}
} else {
// Fallback on earlier versions
return rect
}
}
override public func drawText(in rect: CGRect) {
let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
super.drawText(in: r)
}
}
In your code
label.text = @"some text";
[label sizeToFit];
Beware that if you use that in table cells or other views that get recycled with different data, you'll need to store the original frame somewhere and reset it before calling sizeToFit.
Swift 5
It´s simple, the order of the properties is everything.
titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)