This is the string I use:
CASE 1
var word1 = "عبد الله"
var word2 = "restaurant"
label.text = " \(word1) found your review on \(word2) useful."
Result:
CASE 2
var word1 = "عبد الله"
var word2 = "restaurant"
label.text = "note: \(word1) found your review on \(word2) useful."
Result:
Question
so, how do I make the first word to wrap right? if the first word is arabic, it gets wrapped to the left, but if the first word is english the situation is expected, so how make the word1 to show up when first word on the left?
I tried both
label.textAlignment = NSTextAlignment.Left
and
label.textAlignment = NSTextAlignment.Natural
without any luck.
Unicode has two marker characters (LTR: 0x200E, RTL:200F). These are invisible, but control the direction, I just need to add this \u{200E} to force the wrapping direction.
\u{200E} \(word1) found your review on \(word2) useful.
EDIT:
see full tutorial here, for more info.
UILabel as a subclass of UIView has a variable named semanticContentAttribute which you can set to .foreRightToLeft, it can also be set from the nib inspector through the Semantic pop-up menu in the attributes inspector.
Moreover, you can query effectiveUserInterfaceLayoutDirection property for debugging it's state.
See this for reference.
Now if you need both alignments in one label it will be tricky, either group two labels in a container UIView or see if you can set these values for portions of an NSMutableAttributedString which you can feed to a UILabel.
The textAlignment properties you are trying to set will give you the same effect that MS-Word does to paragraph alignment but wouldn't flip reading direction for language.
Happy coding!
Edit: This is an example of what I am suggesting with attributed strings although when changing the arabic setting to RightToLeft it puts it at the bottom of the string... Maybe the flags need to be combined differently?
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
let myMutableString = NSMutableAttributedString()
//right-to-left
let multipleAttributes: [String : AnyObject] = [
NSForegroundColorAttributeName: UIColor.orangeColor(),
NSBackgroundColorAttributeName: UIColor.blueColor(),
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue,
NSWritingDirectionAttributeName : [NSWritingDirection.LeftToRight.rawValue ]
]
let myAttrString = NSAttributedString(string: "عبد الله", attributes: multipleAttributes)
myMutableString.appendAttributedString(myAttrString)
//some-text
let someText = NSAttributedString(string: " finds ", attributes: nil)
myMutableString.appendAttributedString(someText)
//left-to-right
let multipleAttributes2: [String : AnyObject] = [
NSForegroundColorAttributeName: UIColor.blueColor(),
NSBackgroundColorAttributeName: UIColor.yellowColor(),
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue,
NSWritingDirectionAttributeName : [NSWritingDirection.LeftToRight.rawValue | NSTextWritingDirection.Embedding.rawValue]
]
let myAttrString2 = NSAttributedString(string: "restaurant", attributes: multipleAttributes2)
myMutableString.appendAttributedString(myAttrString2)
label.attributedText = myMutableString
self.view.addSubview(label)
label.sizeToFit()
label.center = self.view.center
}
Related
I'm trying to implement by-design labels coming from Sketch e.g. I need text styles with font size = 19 and line height = 50. So I ended up using NSAttributedString with NSMutableParagraphStyle but was stopped by problem with text being sticked to bottom of UILabel
I've already tried to use lineHeightMultiple and lineSpacing but those didn't give me the line height I wanted so I ended up using minimumLineHeight and maximumLineHeight equal the same
Here is my approach to make NSAttributedString
private static func makeAttributedString(
with attributes: TextAttributes,
text: String? = nil,
alignment: NSTextAlignment = .center
) -> NSAttributedString {
let font = UIFont(name: attributes.font.rawValue, size: attributes.fontSize)!
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = alignment
paragraph.paragraphSpacing = attributes.paragraph
paragraph.minimumLineHeight = attributes.lineHeight // equal 50 in my case
paragraph.maximumLineHeight = attributes.lineHeight // equal 50 in my case
let attributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.paragraphStyle: paragraph,
NSAttributedStringKey.foregroundColor: attributes.textColor,
NSAttributedStringKey.kern: attributes.kern,
NSAttributedStringKey.font: font
]
return NSAttributedString(string: text ?? "", attributes: attributes)
}
I expect result similar to design
but actually getting
Note: setting height constraint to 50 is not applicable because I also need multiline labels but there is the same bug with them
Seems like I've found some workaround myself, maybe it will help someone.
The method is about setting baselineOffset like this:
NSAttributedStringKey.baselineOffset: (attributes.lineHeight - font.lineHeight) / 4
Works like charm:
https://i.imgur.com/a2EOf5R.png
As you can see from the image, the background of the UILabel is set to yellow. The attributed text does not use all the space before wrapping to the next line ("at" should be in the first line). Any way to fix it?
The label is constructed as follows. It is inside a UICollectionView header, and positioned by autolayout
let astring = NSMutableAttributedString(string: "You asked friends, and people at ")
astring.append(NSAttributedString(string:"Pittsburgh",
attributes: [.font: UIFont.boldSystemFont(ofSize: 15)]))
let label = UILabel()
label.attributedText = astring
Yes, odd bug...
One work-around, although I haven't done any testing on it except to see that it works in your case.
Append a "no-width space" character at the end:
let astring = NSMutableAttributedString(string: "You asked friends, and people at ")
astring.append(NSAttributedString(string:"Pittsburgh",
attributes: [.font: UIFont.boldSystemFont(ofSize: 15)]))
astring.append(NSAttributedString(string:"\u{200b}",
attributes: [.font: UIFont.systemFont(ofSize: 15)]))
Result:
Append the ""\u{200b}" in Attributed String in End . hope it it will work ,
I have looked at solutions on stack and they have not helped me. The following is my attempt to change the line spacing for the text in my UILabel. Please can someone advise. I see no effect on my line spacing.
let myText = abstractText.text!
let myParagraphStyle = NSMutableParagraphStyle()
myParagraphStyle.lineSpacing = 5
let myNsAttrStringObject = NSAttributedString.init(string: myText, attributes: ["paragraphStyle":myParagraphStyle])
abstractText.attributedText = myNsAttrStringObject
Your attribute key is not correct in this way, you can use objective-c key NSParagraphStyleAttributeName or swift 4 key NSAttributedStringKey.paragraphStyle:
let myNsAttrStringObject = NSAttributedString.init(string: myText, attributes: [NSParagraphStyleAttributeName: myParagraphStyle])
I'm using
titleLabel.Lines = 2;
titleLabel.LineBreakMode = UILineBreakMode.TailTruncation;
Now long text is broken by a ... in the end.
Now I would like to know if the titleLabel is tail truncated , contains "..." ? Any easy suggestions for this ?? as I cannot see the ... characters in the actual titleLabel.Text field
Your question is similar to Change the default '...' at the end of a text if the content of a UILabel doesn't fit
There is no direct option to access ellipsis(the three dot). You need to do it yourself. Code to count the size of your string, clip the string and add a ellipsis with the color you want when the string exceed the view.
Define a NSAttributesString
let atttext = NSAttributedString(string: text!, attributes: [NSForegroundColorAttributeName: UIColor.redColor()])
Calculate the size of the string
let bounds = atttext.boundingRectWithSize(label.bounds.size, options: [], context: nil)
Do something to the string when it exceed the view
if bounds.size.width > 10 {
//Do something here, like assign a new value to `attributedText` of label or change the color
label.attributedText = NSAttributedString(string: "Labelfdjkfdsjkfdsjkf...", attributes: [NSForegroundColorAttributeName: UIColor.blackColor()])
}
For more detail, you can have a look at the last answer of the question I mentioned above.
I wanted to change the text of a label that says "hello world" such that "hello" is red, and "world" is blue. I'm doing this programmatically and obviously simplifying this example.
Is there a way to do this?
My alternative was to just create two uilabels, and set the attributes of each one accordingly, and then just add them together next to each other, but I thought it would be great if I could just assign the text of a label as per above instead.
By the way it doesn't have to be a UILabel as long as I can just render this text inside a UITableView row.
Thanks!
Here is a small example on how to use NSAttributedString:
var resultString = NSMutableAttributedString(string: "Hello ", attributes: [NSForegroundColorAttributeName : UIColor.redColor()])
var worldString = NSMutableAttributedString(
string: "World",
attributes: [
NSForegroundColorAttributeName : UIColor.redColor(),
NSFontAttributeName : UIFont.boldSystemFontOfSize(13.0)
]
)
resultString.appendAttributedString(worldString)
Then you can assign it to UILabel:
UILabel().attributedText = resultString