Adding UILabel programmatically only by code. Sizing ? (Swift) - swift

I try to add a UILabel by code which works, but not as intended.
With following Code I can see the label but the height of the label is not correct as you can see in the attached screen. I would like the uilabel sized so the height of the label corresponde to the fontsize.
Of course I could simply oversize the UILabels high so the text would fit. But I don't think thats best practice.
How do I size an UILabel based on a fontsize ?
var uilabel1=UILabel();
uilabel1.frame=CGRectMake(0, drawy, screenwidth, ititlesize);
uilabel1.text=sTextViewOptionsTitle;
uilabel1.font = UIFont(name: uilabel1.font.fontName, size: 28);
self.view.addSubview(uilabel1);
var lastelementheigth=uilabel1.frame.height;
UPDATE Solution with sizeToFit()
Thanks for the answer regarding sizeToFit(). This did the trick with some additional code to position the control.
updated Code:
var uilabel2=UILabel();
//uilabel2.frame=CGRectMake(0, drawy, screenwidth/2, DropdownHeigth);
uilabel2.text=sTextSizeTextViewer;
uilabel2.font = UIFont(name: uilabel2.font.fontName, size: iFontsize_Option);
uilabel2.sizeToFit();
uilabel2.frame.origin = CGPoint(x: 0, y: drawy);
self.view.addSubview(uilabel2);
lastelementheigth=uilabel2.frame.height;

You may only need to call -sizeToFit. This will change the label's size to its "preferred" size based on its contents. Then you can reposition the origin or center if desired.

It's been asked before - take a look at:
Replacement for deprecated sizeWithFont: in iOS 7?
The method you're looking for is sizeWithAttributes

Related

Bottom Border for UITextField in Swift

I found this question with a solution to my problem but it still has some misbehavior when I'm using it.
How to only show bottom border of UITextField in Swift
In my Project it seems like the bottom border doesn't know the correct width of my UITextField and is longer than my UITextField. The UITextField has constraints to the SaveArea on the left and right and a constraint to the text above. I would say that the width is defined by the constraints at run time so that the code in the extension should be able to get the correct width. But the way my code is getting the width seems to be wrong. Can someone help me?
Thanks in advance :)
I know you found a workaround but just thought I might add a fix for this if you still were considering using this.
So it seems that your set up was fine but it works a little bit differently on different device sizes.
self.frame.size.width in the extension is not always returning back the correct width of the UITextField in some devices and on orientation changes.
So to get this to work, here are the small changes I made:
extension UITextField
{
func addBottomBorder() {
let bottomLine = CALayer()
// The border should be inside the text field
// so I changed frame.size.height + 5 to
// frame.size.height - 1
bottomLine.frame = CGRect(x: 0,
y: frame.size.height-1,
width: frame.size.width,
height: 1)
bottomLine.backgroundColor = UIColor.black.cgColor
borderStyle = .none
layer.addSublayer(bottomLine)
// Add this so the layer does not go beyond the
// bounds of the text field
layer.masksToBounds = true
}
}
After this, the result should be as you hope:

How to vertically align text of NSSecureTextField in swift for macOS [duplicate]

I have been reading through the various options on how to set the vertical alignment on an NSTextField. I want the text to be displayed in the center and to do it programatically in Swift. Here are the things I have looked so far:
http://www.cocoabuilder.com/archive/cocoa/174994-repositioning-an-nstextfieldcell.html
https://red-sweater.com/blog/148/what-a-difference-a-cell-makes
Vertically Centre Text in NSSecureTextField with subclassing
Get NSTextField contents to scale
vertically align text in a CATextLayer?
One thing I have tried in Swift is to set the following property:
textField.usesSingleLineMode = true
Any tips on the best way to vertically center text would be much appreciated!
This is very hard to do, as Apple makes this very difficult. I achieved it by subclassing NSTextFieldCell and overriding the drawingRectForBounds: method like so:
override func drawingRectForBounds(theRect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (theRect.size.height - 22) / 2, width: theRect.size.width, height: 22)
return super.drawingRectForBounds(newRect)
}
This is just my way to do it, I'm sure there are better ways, which I don't know (yet). And this only works for the standard font size in TextFields (which gives a text height of 22). That's why I hardcoded that. Haven't figured out yet, how to get the height in the cell if you change the font.
Result:
Try this on a playground, it centers the text perfectly, use it on your projects! Hope it helps!
import Cocoa
let cell = NSTableCellView()
cell.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
let tf = NSTextField()
tf.frame = cell.frame
tf.stringValue = "MyTextfield"
tf.alignment = .Center
let stringHeight: CGFloat = tf.attributedStringValue.size().height
let frame = tf.frame
var titleRect: NSRect = tf.cell!.titleRectForBounds(frame)
titleRect.size.height = stringHeight + ( stringHeight - (tf.font!.ascender + tf.font!.descender ) )
titleRect.origin.y = frame.size.height / 2 - tf.lastBaselineOffsetFromBottom - tf.font!.xHeight / 2
tf.frame = titleRect
cell.addSubview(tf)
I have added the NSTextField inside a NSView and centered it.
Another solution was (in an iOS project) to create a UILabel and allow it adjust its size (sizeToFit()) and again embed it inside a UIView.
I personally don't like the calculations in previous answers and the second solution for iOS works for all texts size and row numbers.
I was also facing vertical alignment issue with NSTextField. My requirement involved, rendering a single-line string inside a NSTextField. Additionally,
textfield needed to be resize implying we had programatically resized the font-point-size of the text inside text-field on resize. In this scenario we faced vertical-alignment issues - the mis-alignment was tough to grasp/understand in a straight forward way.
What finally worked:
So, in my scenario a simple,
turn off the "Single Line Mode" in interface builder
for the text-field solved the issue.
The accepted answer works perfectly and here's the Swift3 version.
class VerticallyAlignedTextFieldCell: NSTextFieldCell {
override func drawingRect(forBounds rect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (rect.size.height - 22) / 2, width: rect.size.width, height: 22)
return super.drawingRect(forBounds: newRect)
}
}

Vertically aligning text in an NSTextField using Swift

I have been reading through the various options on how to set the vertical alignment on an NSTextField. I want the text to be displayed in the center and to do it programatically in Swift. Here are the things I have looked so far:
http://www.cocoabuilder.com/archive/cocoa/174994-repositioning-an-nstextfieldcell.html
https://red-sweater.com/blog/148/what-a-difference-a-cell-makes
Vertically Centre Text in NSSecureTextField with subclassing
Get NSTextField contents to scale
vertically align text in a CATextLayer?
One thing I have tried in Swift is to set the following property:
textField.usesSingleLineMode = true
Any tips on the best way to vertically center text would be much appreciated!
This is very hard to do, as Apple makes this very difficult. I achieved it by subclassing NSTextFieldCell and overriding the drawingRectForBounds: method like so:
override func drawingRectForBounds(theRect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (theRect.size.height - 22) / 2, width: theRect.size.width, height: 22)
return super.drawingRectForBounds(newRect)
}
This is just my way to do it, I'm sure there are better ways, which I don't know (yet). And this only works for the standard font size in TextFields (which gives a text height of 22). That's why I hardcoded that. Haven't figured out yet, how to get the height in the cell if you change the font.
Result:
Try this on a playground, it centers the text perfectly, use it on your projects! Hope it helps!
import Cocoa
let cell = NSTableCellView()
cell.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
let tf = NSTextField()
tf.frame = cell.frame
tf.stringValue = "MyTextfield"
tf.alignment = .Center
let stringHeight: CGFloat = tf.attributedStringValue.size().height
let frame = tf.frame
var titleRect: NSRect = tf.cell!.titleRectForBounds(frame)
titleRect.size.height = stringHeight + ( stringHeight - (tf.font!.ascender + tf.font!.descender ) )
titleRect.origin.y = frame.size.height / 2 - tf.lastBaselineOffsetFromBottom - tf.font!.xHeight / 2
tf.frame = titleRect
cell.addSubview(tf)
I have added the NSTextField inside a NSView and centered it.
Another solution was (in an iOS project) to create a UILabel and allow it adjust its size (sizeToFit()) and again embed it inside a UIView.
I personally don't like the calculations in previous answers and the second solution for iOS works for all texts size and row numbers.
I was also facing vertical alignment issue with NSTextField. My requirement involved, rendering a single-line string inside a NSTextField. Additionally,
textfield needed to be resize implying we had programatically resized the font-point-size of the text inside text-field on resize. In this scenario we faced vertical-alignment issues - the mis-alignment was tough to grasp/understand in a straight forward way.
What finally worked:
So, in my scenario a simple,
turn off the "Single Line Mode" in interface builder
for the text-field solved the issue.
The accepted answer works perfectly and here's the Swift3 version.
class VerticallyAlignedTextFieldCell: NSTextFieldCell {
override func drawingRect(forBounds rect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (rect.size.height - 22) / 2, width: rect.size.width, height: 22)
return super.drawingRect(forBounds: newRect)
}
}

Swift get Y coordinate of current element

I got some UILabel which can be pressed to open a menu. When pressed, they call my function with the label itself as a parameter. I make a popover that behave correctly in phone view but I would like to position it when it is on ipad view.
My problem is that I can not get the exact position of the UILabel that was pressed.
I tried
myYCoordinates = label.bounds.origin.y
or
myYCoordinates = label.frame.origin.y
to
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(self.view.bounds.size.width / 2, myYCoordinates, 1.0, 1.0)
But I cant get the good coordinate.
I don't know if it is because my label are in a tableview with 2 section or if there is a way at all.
Thank in advance for the help.
Here is my sceen (cropped du to development confidentiality)
Here is what append when I press my label
And here is what I would like ti to look like
I tried
optionMenu.popoverPresentationController?.sourceRect = label.frame
Based on #Özgür Erzil answer, I found out that I could simply use
optionMenu.popoverPresentationController?.sourceView = label
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(label.frame.width, label.frame.height / 2, 1.0, 1.0)
By setting the source view to my label and using the label width and height to position it.
Thank
if you create your UILabel dynamically, try to set the position when you set it like:
CGRectMake(x, y, width, height)
var label = UILabel(frame: CGRectMake(0, 0, 200, 20))
or if it is in storyBoard, you have to use constraint methods and use autolayout. Explained here

UIButton label text is being clipped

I have a UIButton built in Interface Builder that has a default label. In Xcode, I'm changing the label text dynamically like so:
myButton.titleLabel.text = #"this is the new label";
However, when the text updates, the new string is being clipped down to the same size as the original string and ends up looking like:
this...label
Anyone know why this is happening?
You should use setTitle:forState: to change the title of a UIButton. If you change the title yourself, the button has no indication that it needs to resize the label – you'd end up having to do something like this:
myButton.titleLabel.text = #"this is the new label";
[myButton setNeedsLayout];
but I'm not even sure that would work in all cases. Methods like setTitle:forState: are provided so that you can provide titles for multiple states without having to update the button manually, and so that the button knows that it needs to be laid out with a new title.
Try using the button's setTitle method (rather than setting the title directly on the label). It should force the title label to be resized.
Objective C:
[myButton setTitle:#"This is the text" forState:UIControlStateNormal];
Or in Swift:
myButton.setTitle("This is the text", for: .normal)
An alternative solution is to let the UIButton's inner UILabel to shrink the font size, as UILabels can do :
button.titlelabel.minimumFontSize = 8.0; // or some more adequate size
self.buttonWithLongTitle.titleLabel.adjustsFontSizeToFitWidth = YES;
Call sizeToFit on your button. This will resize the button to fit the text.
If that didn't work you can always determine the string size and adjust the button frame width. In that case you are sure it will fit.
// Calculate the size
CGSize buttonSize = [#"My text.." sizeWithFont:[UIFont systemFontOfSize:15.0]
constrainedToSize:someSize lineBreakMode:UILineBreakModeWordWrap];
// Do whatever you want with the "buttonSize", you can for example adjust your button's frame width
Solution in Swift 4.2
yourButton.titleLabel?.minimumScaleFactor = 0.5 //set whatever you want here to scale
yourButton.titleLabel?.adjustsFontSizeToFitWidth = true
Solution for Objective C
[yourButton.titleLabel setMinimumScaleFactor:0.5];
[yourButton.titleLabel setAdjustsFontSizeToFitWidth:YES];
This worked for me while setting my button up programmatically with all other constraints.
yourButton.widthAnchor.constraint(equalToConstant: yourButton.intrinsicContentSize.width).isActive = true
You can also add "padding" like so
yourButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
Use Autoresizing mask if not selected.
None of the solutions above worked for me. What did was sublclassing UIButton and re-setting the frame of the titleLabel:
Context: My font was Josefin Sans and it does clipping the top part of "Ñ". I can imagine it could happen with any other text using a different font.
open class Button: UIButton {
open override func layoutSubviews() {
super.layoutSubviews()
guard let titleLabel = titleLabel else {
return
}
// Play around to get these numbers
let heightToAdd: CGFloat = 15
let widthToAdd: CGFloat = 100
titleLabel.frame = CGRect(
origin: CGPoint(
x: titleLabel.frame.origin.x - widthToAdd / 2,
y: titleLabel.frame.origin.y - heightToAdd / 2),
size: CGSize(
width: titleLabel.frame.width + widthToAdd,
height: titleLabel.frame.height + heightToAdd
)
);
}
}
Play around with the values widthToAdd and heightToAdd or make them injectable when setting a new title.
It is not a superb solution, but it was the only think that worked for me.