NSMutableAttributedString in UILabel with alternate baselineOffset - ios

I have a case where I want to display some sort of Footnote-Text in a UILabel. The text is prefixed with a number as the corresponding index.
My first idea to solve this problem was to simply create a view-setup with an UILabel for the mark and the text each. This, however, involved a lot of fiddling with constraints and auto-layout, since I wanted to list all footnotes in a table.
Thus I came up with the idea of using NSMutableAttributedString and set the baseline/font-size for the mark and the text respectively. The resulting NSAttributedString could then be used in any Layout with an UILabel.
let footnote: NSMutableAttributedString = .init(string: mark, attributes: [
.foregroundColor: UIColor.myColor,
.font: UIFont.myFont(7),
.baselineOffset: 10,
])
disclaimer.append(.init(string: text, attributes: [
.foregroundColor: UIColor.myColor,
.font: UIFont.myFont(14),
]))
Or so I thought. Seems like the layout of either the UILabel or the UITableViewRow do not like text with alternating baselines, as the UILabel never resized to more 2 Lines. Everything beyond those 2 lines was cut off. Even setting the preferredMayLayoutWidth to help the layout out a bit did not work. It did scale the Label to the correct height, but the text was still missing as if it was cut-off.

So, to answer my own question (and to share this knowledge with whoever might stumble across the same problem), I was able to solve this problem with a very simple (admittedly not very elegant) fix.
All I had to do was to add some text before my mark with the modified baselineOffset. This way, the layout seems to be able to calculate the correct height while still rendering the mark and text properly. Since I did not want any additional text in my cells, I've used a Zero-Width Space character.
let footnote: NSMutableAttributedString = .init(string: "\u{200B}", attributes: [:])
footnote.append(.init(string: mark, attributes: [
.foregroundColor: UIColor.myColor,
.font: UIFont.myFont(7),
.baselineOffset: 10,
]))
footnote.append(.init(string: text, attributes: [
.foregroundColor: UIColor.myColor,
.font: UIFont.myFont(14),
]))

Related

How to use font to write musical sheet

I am trying to make an iOS app that can make possible to write and edit musical sheet.
I was wondering how can I visualise it.
I did not found any complete framework in swift that can make it possible.
But I found this font bravura, but i did not found any example of use.
This is an OpenType Font.
Reading the documentation I should be able to decide through unicode characters, how to change the position of the next element.
But no it doesn't seem to work. At first I thought it was because of the ligatures as not all editors support it, I'm not a font expert and I could be wrong.
So I used the NSAttributedString class to modify these parameters. But the result is still not what is expected.
This is my code :
textView.font = UIFont(name: "Bravura-Text", size: 40)
let text = "\u{E014}\u{EB99}\u{E0A4} \u{E014}\u{EB91}\u{E0A4}"
let attributes = [
NSAttributedString.Key.font : UIFont(name: "Bravura-Text", size: 40)!,
NSAttributedString.Key.ligature : 2
] as [NSAttributedString.Key : Any]
let attributedString = NSAttributedString(string: text, attributes: attributes)
textView.attributedText = attributedString
E014 = Displaying a 5 line staff
EB99 = Lower by two staff positions
EB91 = Raise by two staff positions
E0A4 = The black notehead
This is the result :
result
Any suggestions to make it possible to use this font and its features on iOS?
I would like to write a musical sheet like this one.
Layout of music notation require higher-level layout rather than just displaying a line of text. (Analogous to Web pages using HTML as high-level layout rather than just lines of text.) Fonts can provide the basic symbols, and all of the basic symbols are encoded in Unicode. But you'll need some library that can read a music-notation markup language and layout the content.
You can probably find the kind of resources you'll need at https://www.w3.org/community/music-notation/

Make selected string of text view Bold, Italic, Underline like native "Notes" app of iOS

Is there any help to make selected string of text view Bold, Italic, Underline like native "Notes" app of iOS. Please give me helpful links. I am tired of searching for the whole day. Many Thanks.
I have attached my code, to make attributed string Bold and Italic both like native app of iPhone "Notes".
attributedString.beginEditing()
attributedString.addAttributes([NSFontAttributeName: UIFont.boldSystemFont(ofSize: CGFloat(app_delegate.settings.chatFontSize))], range: range)
attributedString.addAttributes([NSFontAttributeName: UIFont.italicSystemFont(ofSize: CGFloat(app_delegate.settings.chatFontSize))], range: range)
attributedString.endEditing()
But its giving only Italic string, not also Bold. I need both Italic and Bold. Thanks.
The problem in your code is that you are setting the italic font and overwriting the bold one you've just set. What you need is to use UIFontDescriptor with Symbolic Traits as you can see in this SO answer. So just initialize your system font, get its font descriptor and add traitBold and traitItalic to it. Then you just need to initialize your new Font using UIFont initializer init(descriptor: UIFontDescriptor, size pointSize: CGFloat):
Swift 4 code:
attributedString.beginEditing()
let systemFont: UIFont = .systemFont(ofSize: 32)
if let descriptor = systemFont.fontDescriptor.withSymbolicTraits([.traitBold, .traitItalic]) {
let systemFontBoldAndItalic = UIFont(descriptor: descriptor, size: 32)
attributedString.addAttributes([.font: systemFontBoldAndItalic, .underlineStyle: NSUnderlineStyle.styleSingle.rawValue], range: NSRange(location: 0, length: attributedString.length))
}
attributedString.endEditing()
Take a look at NSAttributedString. You can use that to create strings that have mixed attributes at different ranges.
In Objective-C, the mutable version, NSMutableAttributedString has methods like setAttributes(_:range:) that let you change the attributes of an attributed string in a specified range.
So you'd initialize an NSMutableAttributedString starting from a normal String object, and then use setAttributes(_:range:) function to set different attributes like Bold, Italic, etc on a range of the string.
(No, I don't have sample code handy.)
Although the question is old but it may helps someone.
Using NSMutableAttributedString won't solve the problem, because if you type any where before the customised text the range will be different. Therefore, the customisation will shift to satisfy the updated range.
I think using HTML is better solution if you would have a very long string.
You may consider using some open source libraries, like ZSSRichTextEditor
Hope that help.

Changing the color of individual characters in a glyph

As I understand it, a string contains glyphs and a glyph might consist of individual characters. For me this is a problem, as I would like to change the color of some diacritics in a string.
Let's say we have the following string:
วาีม
For this string I would like to make the consonants a different color as it's diacritic. I.e.: I want a different color for วาม and ี.
From my tests it seems that I am only able to color individual glyphs. It seems I can not change the color at a character (diacritic) level. Some example code:
let text = NSMutableAttributedString(string: "วาีม")
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: NSMakeRange(0, 1))
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSMakeRange(1, 1))
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.green, range: NSMakeRange(2, 1))
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.orange, range: NSMakeRange(3, 1))
label.attributedText = text
The above would render as follows:
As can be seen the diacritic is not rendered with a green color.
Does anyone know if there is some way to achieve the result I want?
I doubt you'll find a good way to do this. The glyph for าี in the font is a completely different thing than the glyph for า. For example, in the Thonburi font on my Mac, the former is glyph 1507 and the latter is glyph 78. Each glyph entry in the font is a completely separate little description of how to draw the glyph. For the combined glyph, the diacritic is not a separate thing. The system has no way to know when it's drawing the base character and when it's drawing the diacritic. It's just drawing one thing. So, it can't apply different colors.
I'm completely unfamiliar with Thai, so I'm just speculating for this next part, although it's certainly true for some languages: I suspect there are glyphs for combining sequences which are radically different from what you'd get by just overlaying the component parts on top of each other. So, even in principle, it's not clear that there's a visually separable diacritic shape vs. the base character.
An alternative is to put two labels on top of one another; one containing the text with the diacritics in the colour you want for the diacritics; one on top of it with the same text but without the diacritics, in the colour you want for the text.
When rendering, the identical bits of the text should cancel out exactly, leaving you with text and diacritics in the right colours.

How can I get a custom font weight for the system font, in-between regular and light?

I'm using the iOS system font (San Francisco for iOS 9+) in my custom keyboard extension.
I've noticed the font shown in the system keyboard has a lighter weight than UIFontWeightRegular but it is also bolder than UIFontWeightLight.
How can I implement a font in my own keyboard with the same weight that's used in the stock keyboard?
The systemFontOfSize:weight: API allows you to specify any weight as a CGFloat, and iOS will return the most appropriate font.
For example, instead of UIFont.systemFontOfSize(17, weight: UIFontWeightRegular) you could do UIFont.systemFontOfSize(17, weight: 0). Play with the weight value to determine if you can get a font that appears as desired.
Another option could be to try using HTML & CSS with an attributed string. Using font-weight you can specify a value between 100 and 900, where 400 is equivalent to the normal font weight.
var htmlString = "<p>A</p>"
htmlString += "<style>p{font-family:'-apple-system'; font-size:17px; font-weight:300}</style>"
let htmlData = htmlString.dataUsingEncoding(NSUnicodeStringEncoding)!
let attributedString = try! NSAttributedString(data: htmlData, options: [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding
], documentAttributes: nil)
self.aLabel.attributedText = attributedString
Update: Trying this out, neither solution allows finer control over the font weight. Both will render the text with the closest font for the given weight - Regular or Light but nothing in-between. You may need to resort to custom text drawing if you wish to add a thicker stroke to a thin font. You might investigate drawing via NSAttributedString's drawing API. You may be able to apply a custom stroke width via NSStrokeWidthAttributeName. I have not tried this myself but it was a thought that might be worth investigating.

Swift - iOS 8 - NSKernAttributeName character spacing problems

Part of my application facilitates the drawing of stored string values to a graphics context to be viewed by the user. This is being done with an attributed string with the below Attributes.
//adding the attributes to the NSAttributedString
let textStyle = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as NSMutableParagraphStyle
let textColor = UIColor.blackColor()
let boxTextFontAttributes = [
NSFontAttributeName : font!,
NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: textStyle,
NSKernAttributeName: (7.62),
]
I'm seeing a problem with the NSKernAttributeName character spacing on the output.
I have 2 Strings, both with the same CGRect dimensions (but different y-positions (one below the other)), both upper case, same font & size.
Whenever it comes to a 'thinner' character in one of the strings, such as an "I", it looks to impact the spacing of the following characters.
I basically need to have each character in both strings to be vertically in-line to the string above/below regardless of what character it is? I can only assume that even though it may have a set spacing between the characters, each character still has an individual 'width' of sorts that impacts the rest. Is there a way to standardise this?
Any help would be appreciated - (apologies for not being able to post a picture due to lack of reputation points)
A monospaced font corrected the issue of the character alignment. Some example monospaced fonts available in iOS 8 are Courier & Menlo. Useful post: What is a monospace font in iOS?

Resources