Typography on iOS

    Most information in applications is transmitted through text. Therefore, it is necessary to typeset it a lot, and ignorance of all rendering mechanics entails various problems. For example, a simple task is to add text selection to an existing application. We replace UILabel with a UITextView, and suddenly all the indents go, the text looks completely different or does not fit on the screen at all.

    Under the cut you will find a transcript of Irina Diaghileva ’s speech at  AppsConf , in which she explained why this happens and what settings are best used in a particular case.

    The article will consist of two parts, first we will talk about the basic terms of typography, about fonts and their metrics, and about the most commonly used symbolic attributes. And in the second part we will talk in detail about TextKit and the differences between rendering UITextView and UILabel.

    About the speaker: Irina Diaghilev leading iOS developer at RAMBLER & Co . Over the many years of iOS development experience, she managed to participate in the creation of several applications for large newspaper publishers, in which it was necessary to exercise complete control over the rendering of text .

    Typography Terms

    First, we’ll deal with the basic typography terms, talk about fonts and their metrics, and about the most commonly used symbolic attributes.


    The main term for typography is font. A font is a set of characters that have a similar pattern and have three components fixed: headset, style, and size. A headset is a whole group of fonts that are designed in such a way as to look harmoniously with each other, they have a similar shape to the picture.

    Fonts within the same group have different styles . The mark, in turn, is also divided into three characteristics. We distinguish characters by width, by saturation, and by tilt. There is often confusion between italic and  obliquetracing. These are completely different styles, italics are initially contained in the font file, and it is only similar to normal. And oblique is a software-synthesized distortion of characters from the direct style. And finally, the third component is the size or in another way the size .

    Each character on the printed page is given a specific place, this rectangle is called the skittle area . Its height from the bottom to the top edge is called the size or font size. The system is able to return to us a rectangle that is assigned to the character on the printed page, but in fact its height is not equal to the size. It is called Bounding Rect and consists of the following values: line spacing ( leading) and line height. The height of the line in the general case is also not equal to the size.

    If we look at all the symbols, then they seem to lie on one straight line. This line is called the font line or Baseline , parallel to it runs the middle line of the font or Meanline . And the distance between them is called x-height , which characterizes the height of lowercase letters. The symbol x is taken as a reference, hence the name of the x-height metric. We can also get the height of the capital letters - cap-height .

    And the last two metrics are ascender and  descender. All that goes above Baseline to the highest point of the top extension elements is ascender, and descender is that goes down, respectively, it is negative.


    Now let's look at a couple of lines. The distance from the baseline of one line to the baseline of another line is called lead or leading. Favorite designer's parameter, which we can edit in several ways. First, we can change Line spacing . It is specified in absolute terms and increases the distance only between the lines. The indentation on the first line remains unchanged.

    The next Line Height Multiple setting is relative. This is some value by which each line of text is multiplied. In the figure below, we see that the first line also has an indent. To understand this, in fact, is very important, because as a result of such changes other indentation may occur, for example, for a text element.

    The following two attributes are Minimum Line Height and  Maximum Line Height . They set the string limit. For example, for a given size and a given font, the line height is 200 points. If we set Minimum Line Height = 170, then nothing will change, because we satisfy these conditions. But as soon as we exceed the value of 200 points, we will see that the lines began to increase. And also pay attention to the figure below, the first line has some indentation. Similarly to Maximum Line Height, increase the value - nothing changes, because Satisfy the conditions. Just starting to reduce - the lines begin to converge.

    To select any of these settings, you need to sit down with the designer and see what exactly he set in his graphics editor, and select the appropriate attributes. Otherwise, then there will be problems with the alignment of text elements.

    And the last attribute is Baseline offset , which also visually distances the rows from each other, but is designed for a slightly different one, namely for upper and lower indices, for example, x  2 , the base logarithm. Reduce the font size and shift it to some specific value relative to Baseline using this attribute.


    Now let's move the whole paragraphs. Here, in fact, everything is simple, no surprises, we can increase the values ​​after the paragraph - Paragraph Spacing , we can set Paragraph Spacing Before , and then indentation will be added before the paragraph. And note that the first paragraph remains in place, as there is no paragraph before it and accordingly nothing was added before it.

    We can shift the first line (First Line Head Indent ) and also set the indent for all other lines both on the left (Head Indent) and on the right ( Tail Indent ). In this case, if the Tail Indent is set to negative, the indent will be at the right border, and positive sets the indent from the left border.

    Kerning and Tracking

    If we stack symbols one after another, then, due to the specifics of the symbols themselves, the overall picture will not turn out very well. For example, in the figure below, the characters “T” and “o” are very distant from each other, they want to be brought closer together. And “r” and “n”, on the contrary, stuck together, I want to move them away.

    For this, we came up with two concepts: kerning and  tracking . They always go together, because characterize one value - intersymbol spaces. Kerning is set for a specific pair of characters and is written in the font file, forming an entire kerning table. And tracking is set for a range of characters or the entire document, without reference to specific characters. Those. if we enable kerning (it is enabled by default), we will see that the characters began to be displayed differently. We can both increase and decrease this value. In iOS, we can only set tracking and somehow modify the value that is written in the font file.

    Symbols and glyphs

    Those who have ever worked with text already know that there are methods that translate character ranges into glyph ranges and vice versa. What is it and why their number may not match? A symbol is a semantic unit of a language , it is a letter, number, mathematical operation. And  Glyph is her visual representation . And their number may not coincide when using ligatures . By default, mandatory ligatures are included in iOS, and we see that two consecutive "l" characters turned into one Glyph, there were 5 characters, and there were 4 glyphs. We can also include all the ligatures that are registered in the font file, and then we will get even more beautiful elements, as in the picture below.


    Now let's deal with the TextKit framework, which appeared in iOS 7 and provides us with great opportunities in  editing text . It consists of a specific set of classes and protocols for working with text, its main elements: Layout Manager , Text Storage , Text View and  Text Container . To understand what each of them is responsible for, they often draw an analogy with the MVC paradigm .

    Text Container and Text Storage are Model or data. Layout Manager - Controller. Text View - respectively View. Now a little more about each of them.

    Text storage - this is a repository. It contains information about symbols and their attributes, ensures that the data is consistent, notifies the Layout Manager that there have been some changes in the data.

    Text Container  is also a model, because it supplies the Layout Manager with fragments of lines in which it is necessary to draw text, in addition, it defines exclusion areas that the text will wrap around.

    And finally, the Layout Manager, as befits a controller in MVC, is responsible for a lot of functions. Firstly, it keeps track of Text Storage and Text Container. Generates glyphs from characters, translates ranges from one to another, and directly draws glyphs.


    To initialize a Text Kit stack, you must first create a Text Storage and initialize it with some attribute string. After that, you can create a Layout Manager and add it to Text Storage. Moreover, we can add as many Layout Manager as we want.

    For example, when several representations exist for the same data. After that, create a Text Container and add it to the Layout Manager. By analogy, we can add it as many times as we need, for example, for multi-column layout. And finally, the last optional step is to create a Text View, to which we pass the Text Container, or we can draw glyphs directly through the Layout Manager.

    UITextView and UILabel

    All standard UITextView and UILabel elements that are responsible for rendering text already have an initialized Text Kit stack, but they look and render text completely differently. In the figure below, no additional settings except the font are indicated, but we see that the text looks completely different. Let's see why. Firstly, with a UITextView, the text does not start from the very left edge. The setting of lineFragmentPadding of the Text Container is responsible for this , which sets the indentation of the fragment of the line to the left and right. Those. if we turn it off, the text will move to the very edge.

    There are also indents above and below, and by default they are 8 points. If we turn them off, we will see that the text went up. And the last thing that catches your eye is the line spacing or leading. The fact is that UITextView by default uses the leading one specified in the font file, and UILabel does not, hence the difference. In Layout Manager, we can turn off this setting and get exactly the same display as UILabel.

    Many people do not like to use Auto Layout and calculate the text height with frames, most often using the boundingRectWithSize method. There are a lot of negative reviews about this method, but in fact, you just need to pass the correct parameters to it. That is, firstly, you need to pass Size correctly, specify the correct width, taking into account all the indents. If we consider the height of the text for the Text View, then we must not forget to subtract the indentation from the fragment of the LineFragmentPadding line from the width of the Text View , and also subtract the indentation from the Text Container. And only this width is already passed to this method.

    The attribute string cannot know where it will be displayed in a UILabel or UITextView. Therefore, she needs to transmit some additional information, namely some options that she will use when calculating the height of the text. We are interested in two options. UsesLineFragmentOriginwe pass it when it is necessary to calculate a multi-line text. And the second setting: whether to use the standard font leader in the calculation. For UILabel, we should not pass this setting, but for UITextView, if this option is enabled in the LayoutManager, we must not forget to pass it. Then this method will return the correct height.

    Indentation in a UITextView

    You probably wondered why we needed two settings: Line Fragment Padding, which sets the indentation on the left and right, and Text Container Inset, which also allows you to set the indentation on the left and right. Why did Apple come up with two whole settings?

    Let's say we are typesetting an e-book and we want to place a static image in the center that the text will flow around. This is set very simply, the Text Container has an array of UIBezierPath exception areas. We just take the frame of this picture, translate the Text Container into the frame and give the Text Container so that it wraps around this area. But in the example above, we see that the text is closely adjacent to the picture - this is not very beautiful. To do this, Line Fragment Padding will help us.

    In the figure above, fragments of lines and Text View Background Color are highlighted to make it more visible. If we edit the Text Container Inset , the indent is added around the entire perimeter of the text, and if we edit the Line Fragment Padding, then each fragment of the line will add the value that we specified to the left and right. Those. the text looks completely different and does not fit close to the picture. That's it for this Line Fragment Padding and invented.


    Especially observant noticed hyphenation by syllables, and this is the next TextKit chip, which allows you to make hyphenation in one line of code. Those who have ever worked with Core Text know how painful this is and how difficult this process is.

    First you need to determine the language, insert possible hyphenation points, then insert the hyphen in the right place, calculate all this. Now we can ask HyphenationFactorLayout Manager, and then hyphens will be added to the entire text. Or we can set the NSParagraphStyle object, then hyphens are added for the desired paragraph. The HyphenationFactor value ranges from 0 to 1. Zero means there will be no hyphenation at all; the unit that they must always be added when the text does not completely fill the line; and an intermediate value means that if the text is less than the specified number of percent, then we are trying to insert hyphens.

    We have already examined how to wrap around a text. And, what if we need to add a picture directly to the text and this picture should be displayed along with the text. This is also done very simply, we create an NSTextAttachment, add a picture to it, wrap it all up in an attribute string and work on like with a regular NSAttributedString. But there are nuances, we can not set any desired size of this picture, i.e. the size of the characters with attachment will be equal to the width and height of the image itself. And in order to somehow change or shift it, you must inherit from NSTextAttachment, override one method and add some indentation of your own.


    If we want to extend functionality, we inherit from NSTextStorage, LayoutManager or TextContainer. If with the last two everything is simple, then with NSTextStorage you have to tinker a bit. Because NSTextStorage is actually a cluster class. Those. creating an instance of NSTextStorage we do not know which class instance will return to us. This imposes additional restrictions on inheritance. First, we must provide our data warehouse, it can be some kind of attribute string, and also override the two methods for reading and modifying the characters and attributes in this string.

    This may be necessary if we, for example, make some kind of chat room and want to remind all speakers that they will have a buffet dinner tonight, so that no one misses, we want to send a notification to the entire channel. We're writing@channeland it is automatically highlighted.

    To implement this, NSTextStorage has a processEditing method. The system calls it on its own when we notified the LayoutManager that a change has occurred. Using a regular expression, we need to find all occurrences of certain characters and add or vice versa remove some attributes.

    To add some kind of custom rendering area, you also have to tinker a bit, you just can’t do this out of the box. We inherit from the NSTextContainer object, and when the LayoutManager supplies us with fragments of strings, we use some algorithm to begin to determine the areas in which the text should be drawn.

    In the picture above, a rather complicated UIBezierPath created from svg images. Enumeration searches for the intersection of the source fragment of the string with UIBezierPath. Only the desired piece is returned to the LayoutManager, and the rest of the line is written to the RemainingRange, which will come at the next iteration.

    So, the Text Kit allows you to:

    • Add dynamic text formatting.
    • Define arbitrary drawing and flow areas.
    • Use TextAttachment.
    • Wrap words in syllables.

    And also the Text Kit helps to implement some other interesting features, such as Dynamic type or text animation.

    And finally, some useful links:
    James Felici “Typography. Font, layout, design »
    Text Programming Guide for iOS
    Attributed String Programming Guide
    Getting to Know TextKit
    Butterick’s Practical Typography

    And contacts of Irina Diaghileva:

    We remind you that this year AppsConf mobile development conference was removed from RIT ++ as a separate event and will be held on October 8 and 9 . We plan to organize a large-scale event , gather activists from all Russian communities of mobile developers, submit more than 60 reports to more than 500 people.

    Of course, we  are looking for speakers , and we will be glad not only to recognized, well-known masters, but also to  new people . We want to emphasize that you should not be afraid to submit an application without a lot of experience in public speaking - in order to make the report classy, ​​we haveschool of speakers , including in the format of a telegram channel .

    Until early June, early bird tickets are available at the lowest price.

    Also popular now: