Vertical alignment of iOS custom font in different languages - ios

I am using a custom .ttf font called Classic Robot in my iOS app. I am trying to add Japanese translation and this font appears to not support Japanese characters. This is not a problem initially because it appears iOS automatically changes the font to the system default font which can support Japanese.
My issue is that these two fonts have different vertical alignment when rendered by iOS as in the below pictures. As you can see, the Japanese font is aligned near the top of the white box (which is the frame) whereas the English font sits somewhere near the middle. This makes it difficult for me to layout text properly. Does anyone know why this might be the case?
I believe it might have to do with the ascender and descender properties on the iOS font I cannot be certain.

Your question is: "Does anyone know why this might be the case?"
The answer is that the ascender property of the Japanese font is smaller than the Classic Robot one. This can be fixed by generating a custom Japanese font that has an ascender property large enough to make it match the spacing you get from the other font. This can be done by downloading the Apple Font Tool Suite and following the instructions posted in this answer.
Also for buttons you can solve the issue by increasing the insets:
myButton.contentEdgeInsets = UIEdgeInsetsMake(15.0, 0.0, 0.0, 0.0);
You can specify a different value for each of the four insets (top, left, bottom, right). A positive value shrinks, or insets, that edge—moving it closer to the center of the button. A negative value expands, or outsets, that edge. This works for the button image and button title.

Related

Edit the spacing between lines in any of Delphi FMX text components

is there a way to alter the spacing of any Delphi FMX component ? all are doubled spaced between lines i believe, i'm sure there is a way to edit the spacing between lines. the most important that it work for FMX
The difference between the two screenshots isn't that they have different line heights or line spacings.
The difference is that the left application is using a variable-width font, while the right application is using a fixed-width (monospaced) font.
You can see this extremely clearly in the top centre part of the image, where you have four full stops (....).
I assume you consider the right screenshot to display the desired appearance. If so, the solution is to change the font in the left application to a fixed-width (monospaced) font.

iOS UILabel and avoiding clipping of diacritics with custom font

First of all, there are many questions on StackOverflow, but none that fully answer this question.
The problem is mainly, but most likely not limited to, Thai and Arabic diacritics when rendered with a custom Latin-only font, using the text property of a UILabel. Which is also intrinsically sized in an auto-layout. I've already done everything Apple suggests, playing with the settings mentioned in their documentation, WWDC videos, as well as questions on StackOverflow (e.g. clipsToBounds = NO, etc.). Keep in mind, only my custom font setup clips in my scenario, not the iOS system font (.SF-UIDisplay), and not even the iOS system provided Helvetica or Helvetic Neue. The custom font has been checked and rechecked, and at this point the conclusion, iOS is the anomaly across all platforms, even macOS. To be even clearer, the same clipping behavior as the custom font can be seen with SF Pro, a font provided by Apple themselves here: https://developer.apple.com/fonts/
This question is about the most proper, least intrusive, and most complete way to do what is necessary to not clip diacritics. Meaning, how would you do this, ideally, from scratch.
All of my font research and test runs have led all those involved in this problem to believe that Apple has implemented special treatment specifically for their system fonts in UILabel, to avoid diacritic clipping. So making that an assumption, I'm also assuming the font is ok, and I'm looking for solutions that do not involve editing the font.
In my tries to use the font, the first thing to go wrong was vertical clipping of the ascender diacritics of Thai glyphs:
นื้ทั้มูHello
This means the glyphs of the font Thonburi when they cascade from the custom Latin-only font. The fix from this point, was to use a custom font only for Thai without any Latin characters, so it could be defined as the primary font, and cascade to the previously mentioned Latin-only custom font. After all this, the custom Thai font still has horizontal clipping issues on diacritics that come at the end of the text:
Worldฟล์
So now I am at a loss for anything further that font management puppetry can do (though still open to suggestions), and I am moving on to more code-centric fixes. I've seen quite a few questions and answers mentioning subclassing UILabel, but I'd like to know what this would look like that could accomplish what I've described.
I'd also like to know if just opting out of UILabel would be an option for anyone. Meaning would writing something from the ground up with TextKit be worth it to avoid all these bugs that seem to only plague iOS, and specifically UILabel.
At first I thought this was a problem with the framework but it's not, it's just a strict enforcement of a font's metrics. And in probably everything but web/app development, fonts are not rendered so strictly, which is why this problem rarely comes up. Fonts have a number of metrics that tell the program rendering it onto the screen how to render it, most importantly how to handle padding. And UILabel (and UITextField, and likely others) applies these metrics strictly. And the problem for us is that some fonts are very decorative and are often too thick or oblique to fit perfectly into the square canvas that each character must fit into (this is especially the case with accents, like umlauts). This isn't a problem outside of web/app development because when a character doesn't fit into its canvas, like a very thick, wide, and oblique W, the program just shows it anyway, and that's why a low-hanging g might spill into the line below it. But if that g was rendered in a single-line UILabel, because of how strict the font-metric enforcement is in iOS, that low-handing g is clipped.
Subclassing UILabel (in the case of UILabel) and overriding its intrinsicContentSize to add some extra padding is not a good idea, on further research. For one, it's kind of hacky, but more importantly, it produces constraint warnings in the debugger. The true fix, and the only acceptable fix AFAIK, is to edit the font's metrics.
Download a program like Glyphs (https://glyphsapp.com/), open the font, open the Font's Info, and in the Masters tab, give the font the proper ascender and descender values. To best understand how these values work, open the San Francisco font in the program and see how Apple did it (it's the font they made specifically for macOS and iOS development). As a side note, if you use this app, when you're editing the font's info, go into the Features tab as well, delete all of the features (using the minus icon in the lower left) and hit Update to let the program manage the font's features for you.
The last hurdle is clipping at the leading edge (not the top and bottom) which the ascender and descender metrics don't address. You can use the Glyphs program to edit the canvas size of individual characters to make sure they all fit but that changes the complexion of the font because it changes the character spacing too noticeably. For this problem, I think the best solution is to simply use attributed strings for your labels and text fields. And that's because attributed strings let you safely edit padding without hacking into intrinsic sizes. An example:
someLabel.attributedText = NSAttributedString(string: "Done", attributes: [NSAttributedString.Key.font: UIFont.blackItalic(size: 26), NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.paragraphStyle: NSMutableParagraphStyle.kItalicCenter])
For convenience, I extended NSMutableParagraphStyle since I use this font all over:
extension NSMutableParagraphStyle {
static var kItalicCenter: NSMutableParagraphStyle {
let s = NSMutableParagraphStyle()
s.alignment = .center
s.firstLineHeadIndent = 2
s.headIndent = 2
return s
}
}
This label will push the font forward a couple of points to prevent clipping.
I was trying to solve similar problem with diacritics in Arabic and found workaround:
I have a UITableViewCell with UILabel with arabic text, it's diacritics were cut sometimes
I overrided - (void)drawRect:(CGRect)frame to directly draw NSAttributedString on UITableViewCell
Also I decreased alpha self.arabicLabel.alpha = 0.1; to draw manually on top of label position, I still keep it to calculate cell's height
- (void)drawRect:(CGRect)frame {
[super drawRect:frame];
if (self.viewModel == nil) return;
NSAttributedString *string = [self.viewModel arabicStringWithTajweed];
CGRect originalRect = [self convertRect:self.arabicLabel.frame fromView:self.arabicLabel];
[string drawInRect:originalRect];
}
The core problem on iOS is font substitution. You are specifying a latin font, the font does not contain glyphs for the characters that will be rendered, the system uses a different font to draw the glyphs, but it is still measuring based on the original font.
Option 1, the most robust option, is to manually choose fonts that include glyphs for the characters you will render. When the font assigned to UILabel, or the attributed string it is rendering, contains all the glyphs that will be rendered, and that font has good metrics as most system fonts do, then nothing will be clipped.
Option 2, manually measure the string using glyph bounds. Make a subclass of UILabel and override textRectForBounds and possibly drawText. Measure the string with .usesDeviceMetrics. This is slower that measuring by font metrics and produces different results. For example, the strings "a" and "A" will measure differently.
Option 3, use baseline offset and line height multiple to make room for the diacritics that are being clipped. Choose or compute constant values for each font for each language, and apply those to the attributed string of the UILabel. This can compensate for the different in font metrics between the font you chose and the font that is actually rendering glyphs. We had localized strings with the worst case clipped characters for each language, and used those to compute the offset and height. Different fonts have different worst case clipping characters.

Align two UILabel texts

I would like to align the start of the text of two UILabels. I aligned the two UILabels (with the yellow and grey background) and used sizeToFit: to shrink the UILabels to the content but the text is not perfectly left aligned. There is a gap on the left. The gap is bigger or smaller depending on the first character. I would like to align the red lines in the following picture. There is even a small gap with the small font in the grey UILabel but it's barely visible.
With the Z character the gap is smaller but still visible by the yellow area left to the Z
A simple UILabel alignment does not help for my specific problem, because the text content is dynamic and not static. So there could be any combination depending on the data I get from the backend. Therefore I was hoping for a UIFont or UILabel attribute that could return the size of the gap based on the current rendering of the text.
I know that there are great UIFont related attributes like baseline, capHeight and ascender one can access to align text but there seems to be no attribute that would return the value of this gap on the left.
If this doesn’t need to be two UILabels, you could have one with attributed text. Then both lines would be subject to the same layout.
I haven't tried the GUI which people have been posting Screen Shots of, however... the behaviour is consistent with the very nature of typography.
The font sizes are completely different, therefore the width of an em is different, subsequently the letter-spacing is also different.
See this: http://www.w3.org/WAI/GL/css2em.htm for more information.
I know this answer doesn't give you what you have asked for, however it should explain why this is happening.
For customisation such as this (if HTML and CSS) I would use a negative / positive margin on the sub text, however seeing as you are using backgrounds use padding (or the equivalent in your GUI).
Use attributed text of UILabel
set indentation as per your requirement
ref screen shot
Select both the labels and add a constraint called align leading edges.

Unique multiline UILabel looks using auto layout

I have a multiline UILabel that I'd like to look similar on different devices (iPhone only). If it was a single line, I'd simply place the auto layout constraints and enable Autoshrink and set the Minimum Font Scale.
The height of the label is dynamic is calculated based on text. To do that, I need the font, which should also be dynamic. The hack I could do is place an invisible label, and set the text I want to fit in a single line into it and calculate the font, but it seems too hacky.
Another thing I'm not that familiar with are size classes. But from what I've read, the same class is shared between all portraits, meaning 3.5, 4, 4.7 and 5.5 inch devices would be bound to the same class, therefore I couldn't use the separate font value?
How would I implement the 'font scaling' for multiline labels so I'm getting similar look on different screen sizes?
If by similar look you mean that the same words appear on each line, I don't think it's possible.
If the label height is dynamic based on the amount of text, the label will simply expand to the height required to show the text with the specified font size.
Font scaling only kicks in when there is not enough space to display the text with the specified font size. Therefore, you must constrain the height or number of lines.
I was able to approximate this using a multiline UILabel with font scale of .5. I set an Equal Heights constraint between it and its superview, with a multiplier of .25. See screenshots below.
In this approach, you would have to dynamically change the Equal Heights multiplier based on the amount of text you have.

iOS: Modify a font height, width, and spacing independently when creating PDF

In an iOS app I need to use a specific font but each character needs to be taller, thinner, and the spacing closed up to fit correctly. Is it possible to stretch/squish a font programmatically?
When you're adding text to a PDF file there are multiple ways to influence how the text is going to appear. The most generic way (and the way that might actually be sufficient for you) is to scale the text matrix:
void CGContextSetTextMatrix ( CGContextRef c, CGAffineTransform t );
As mentioned in the comment by #mkl, you can provide a matrix that will scale up in the Y direction while scaling down in the X direction. The effect will be that the letters are stretched out vertically and squished horizontally.
Normally I would expect you don't have to touch the spacing in that case, as spacing will be "squished" together just as the other characters.
Just in case that isn't sufficient, PDF actually does provide a way to change the spacing between characters too:
void CGContextSetCharacterSpacing ( CGContextRef context, CGFloat spacing );
While Apple's description talks about "additional space" to add between characters, the PDF specification and I suspect Apple's implementation as a result allows the spacing value to be both positive and negative. A negative value would have the effect of moving the characters closer together.
Seems like the best option would be to create your own custom font.
You are able to change the kerning of your font (the space between the letters) and the thickness/thinness of the font, however you probably aren't able to edit the height of the font, unless you edit the bounding box the font is inside of to scale the letters differently.
You might also want to consider using a different font...or if you're REALLY hardcore you can edit the font yourself using photoshop/illustrator.

Resources