Mastering the dynamic text in IOS8

Source: Internet
Author: User
Tags home screen notification center truncated

    • Original link: Swift programming 101:mastering Dynamic Type in IOS 8
    • Original Author: Kevin McNeish
    • Development technology Front www.devtf.cn
    • Reprint statement: This translation has authorized developers to enjoy the exclusive right to reprint, without permission, not reproduced!
    • Translator: Kmyhy

Apple claims to encourage third-party apps to support dynamic text. However, if you try to implement this feature in the app, you'll find a lot of pits (such as static cells and custom cell styles). In this article, we will introduce the mechanism of dynamic text and its application in various scenarios. We'll also introduce some swift code, which will greatly help you implement dynamic text in your app.

What is dynamic text?

In IOS7, Apple introduces the concept of dynamic text. Dynamic text allows the user to modify the app's font size through the Setup program (only for apps that support dynamic text).

For users with poor eyesight, it is easy to increase the text font, on the other hand, for better-sighted users, you can change the font size to accommodate more content on the same screen.

To modify dynamic text settings in the Settings app, select the larger font, universal--accessibility, 1. The user changes the size of the font by dragging the slider bar. To use a larger font, you can turn on the "larger fonts in accessibility" switch at the top of the screen.

Figure A larger font setting

Figure 2 The diagram on the left shows the display of the contact app under the minimum font, and the graph on the right shows the maximum font when the larger font in accessibility is not turned on.


Figure--small font and large font for the contact app

The following is a system-built app that supports dynamic text:

    • Information
    • Calendar
    • Map
    • Memo
    • Health
    • Event Reminders
    • Contact
    • Weather

Because these apps support dynamic text, users will also require third-party apps to support dynamic text as well. Let's look at the final effect first.

Run the sample app

Let's get the project check out first. You can download the sample project [here] (Http://www.iosappsfornonprogrammers.com/media/blog/iDeliverMobileDynamicType.zip).

    1. In Xcode, open the Idelivermobile.xcodeproj file.
    2. Before running the program, open the Xcode->open->developer Tool->ios Simulator menu.
    3. In the Emulator menu, select Hardware->device->iphone 5S.
    4. Then, open the Setup program and find General->accessibility->larger Text. Drag the slider to the right to the maximum.
    5. Back to Xcode, click Scheme and select iphone 5S from the list of devices.
    6. Click Run, run the program in the emulator, and you will see that the fonts are still small fonts. Obviously, our app does not yet support dynamic text.
    7. Go back to Xcode and quit the app.
Using text styles

Currently, the font names and sizes of all UI controls in the sample program are hard-coded. To support dynamic text, we need to replace these hard-coded content with a text style.

Text styles are concepts that resemble "styles" in a word-processing program. Styles allow us to specify the font of a piece of text in a way that is relative to the size and weight of the word. Figure 3 lists the optional font styles.

Figure 3 – Text styles used in dynamic text

Let's give it a try first.

    1. In the Project Navigator window, select the Main.storyboard file.
    2. In the deliveries scene, select the Feng Wong tab, open the Properties panel, and change the font to headline (Figure 4).

      Figure 4– Set the font to headline.
    3. Select the address label and set the font to Subhead.
    4. To preview all dynamic text effects, set the address label's autoshrink to the fixed Font Size (Figure 5). This will cause the text of the address tag to be truncated, but then we'll fix the problem.

      Figure 5– Setting the address of the font to Subhead, autoshrink as the Fixed Font Size
    5. Click Run and run the program in the emulator, and you will find that the font size has changed (Figure 6).


Figure 6– Dynamic text is already working.

Note that in order to accommodate the large text, the line height is slightly higher.

Now, let's look at what happens when the user changes the font size in the Setup program.

    1. If IDELIVERMOBILECD is not started, click the Run button in Xcode.
    2. When the app starts, press shift+command+h and cut to the home screen.
    3. Open the Setup program, find Larger Text, accessibility, general, and drag the slider to the left to reduce the font size.
    4. Press Shift+command+h to return to the home screen and reopen Idelivermobilecd. Note that the font for the label has been smaller (Figure 7).

      Figure 7–the Fonts the change dynamically.
    5. Back to Xcode, exit the program.
Dynamic text and template cells

The example you see actually corresponds to the following action:

    1. Set the content of the table view to Dynamic Prototype (live template)
    2. Set the cell's style to any of the built-in types

As you can see in Figure 5, the table view in the example does use a template cell.

If you select a cell in the table view in the deliveries scene, in the properties panel you will see that its style is subtitle (Figure 8).

Figure 8– The style of cell is Subtitle.

You will understand that Table view's static and dynamic cells are distinct.

Line wrapping of label text

In some iOS built-in apps, Apple allows text to be truncated after the font is enlarged. In the Contacts app, you'll see such an example in your email address (Figure 9).


Figure 9–email Address is truncated

In your app, you can allow text to be truncated, or go to the next line. Now, let's see how to break the line.

In the deliveries scene, select the Detail Text tab, open the Properties panel, and set the number of lines to 0. This causes the email address to wrap (Figure 10).

Figure 10– Label text exceeds line height

However, iOS does not calculate the row height correctly. Next we'll discuss the row height of the dynamic cell.

Dynamic Row Height

When you use dynamic text in a table view, the row height of the table must also automatically adapt to changes in font size. Apple offers 3 ways to solve the problem:

    1. Modifies the RowHeight property of the table.
    2. Implement Tableview:heightforrowatindexpath: Protocol method.
    3. The adaptive size of the cell.
Using the RowHeight property

Although the row height of your table should be calculated dynamically, you can still use the RowHeight property as in the past. Whenever the font size changes (we'll talk about how to get notifications later), we all need to recalculate the new row heights and set the RowHeight property of the table.

The advantage of using the RowHeight property is speed. It provides optimal scrolling performance because no calculations are required when the user scrolls the table.

The downside is that we have to manually calculate the correct row height. In addition, all cells must use the same row height.

In IOS7, the default row height is 44, and in IOS8, the default row height is uitableviewautomaticdimenssion (a constant, equal to 1). If you want to use the RowHeight property, you need to set its initial value in the Properties panel or in the Viewdidload method.

Implementing the Heightforrowatindexpath Method

We can use the Tableview:heightforrowatindexpath: method to calculate the row height of each row separately.

There is no obvious merit in this approach. The row height of each row is queried in advance, regardless of whether the line has been created. If your table has thousands of rows, this can result in a performance delay.

Adaptive size Cell

If you use adaptive size cells instead of using the RowHeight property, we do not have to set the Estimatedrowheight property or implement Tableview:estimatedheightforrowatindexpath: Protocol method.

The steps to create an adaptive size cell are as follows:

    1. Before each cell is drawn, it uses the Estimatedrowheight property or invokes the associated delegate method.
    2. When the table scrolls, the row is about to be displayed to the screen when the cell is created.

    3. The cell is queried for its size.

    4. If this height is different from the estimatedheight, adjust it with this height.
    5. Displays the cell.

In the 3rd step, there are two ways to calculate the height of a cell:

    1. Automatic layout
    2. Calculate size Manually

Table view invokes the Systemlayoutsizefittingsize method for each cell. The method returns whether the cell has implemented layout constraints, and if so, the automatic layout engine is responsible for specifying the size of the cell.

If you do not implement your own layout constraints, TableView calls the cell's Sizethatfits method. In this method we can calculate the cell height and return it--and the width of the cell is calculated.

Using automatic layout in dynamic text

Let's try the automatic layout in the sample project to see how to use it in dynamic text. First, you need to determine whether the storyboard supports automatic layout.

  1. Click on the white background of the storyboard
  2. Open the Files panel. Under the interface Builder Document column, make sure that use Auto Layout is selected (Figure 11).

    Figure 11-Check the use Auto Layout
  3. Modify the style of the table cell for the deliveries scene to custom. Select the table cell, open the Properties panel, and set the Sytle to custom. This will delete the two tags of the cell.

  4. It is very easy to change the height of a cell in IB. Click the gray area of the table, and in the size panel, set the Row height to 60.

  5. Drag a label from the object library into the cell, and you can see its horizontal and vertical conductors, as shown in 12.

    Figure 12-Add a label to the cell

  6. Drag the resizing handle on the right side of the label, dragging it to the right until the vertical traverse reaches the position shown in Figure 13.

    Figure 13– Setting the width of the label
  7. Keep the label selected, open the Properties panel, and set the font to Headline,tag to 1.
  8. Drag one of the tabs below the first one to make the wire 14 as shown.

    Figure 14– Adding a 2nd label
  9. Drag the resizing handle on the right side of the label to the right until its vertical wire aligns with the vertical wire of the first label.
  10. Keep the label selected, open the Properties panel, set the font to Subhead,lines to 0,tag to 2. Set lines to 0 so that when the label displays long text, it wraps itself.
  11. Select the headline label above the cell.
  12. Click the Pin button in the lower right corner of the IB editor (Figure 15), and in the pop-up window, uncheck the Constrain to Margin box and click on the 4 margins on the top half of the window to make it appear as 4 red lines. This allows the top, bottom, left, and right 4 edges of the label to be aligned to the nearest control, respectively. Then tick the height and click the Add 5 Constraints button.

    Figure 15– Adding a layout constraint to the upper label
  13. Select the Subhead tab below the cell and click the Pin button.
  14. Exactly the same as the headline tag: Deselect the Constraints to Margin option, select 4-side alignment, tick HEIGHTG, and then click the Add 5 Constraints button.
  15. Continue to select the Subhead tab and open the size panel.
    Click the Edit button to the right of the height constraint (Figure 16) and change the operator to "great than or equal to". This causes the height of the label to automatically match the number of lines of text.

    Figure 16– Modifying the height constraint operator
  16. Then the heading tag is repeated above the action. Click the Heading tab, and in the size panel, click the Edit button for the height constraint to change the operator to "greater than or equal to".
  17. Then modify the code of the table View controller. Select the Deliveriesviewcontroller.swift file. In the Tableview:cellforrowatindexpath: method, modify the code to:

    This code uses the Viewwithtag method to obtain a label for the specified tag value. The last line of the highlighted part of the code is not less, because the label will not wrap correctly at some point, so you need to set the Prefferedmaxlayoutwidth property to the current width to fix the problem.
  18. There are a few more places to change. Pull to the top of the Deliveriesviewcontroller.swift file and add the code to the Viewdidload method:

    Set the Estimatedrowheight property of the table to the correct height of the cell. Set the RowHeight property of the table to uitableviewautomaticdimenssion and tell iOS that we need it to resize the cell automatically. Let's take a look at the running effect!
  19. Go back to the simulator, open the Setup program and set the text size to maximum. Click the Xcode Run button and when the program runs, you can see that the email address has been wrapped (Figure 17)!

    Figure 17– e-mail address line-wrapping
Changes to a font on a custom cell

Now, when the deliveries scene loads for the first time, the labels in the table are displayed in the font size that the user has set in the Setup program. Obviously, when a cell uses the built-in subtitle style, if the user changes the font size, the font size on the label changes as well. Unfortunately, if you are using a custom cell, this mechanism is not valid. Let's test it first.

    1. Click the Run button.
    2. When the app launches, press Shift+command+h to return to the home screen.
    3. Open the Setup program, enter the General->accessibility->larger text interface, drag the slider to the left, and change the font size to small.
    4. Press the SHIFT+COMMAND+H key to return to the home screen and switch to the IDELIVERMOBILECD program. We found that the font of the label text did not change in the slightest. Close the app and we'll fix it.

To enable a label (or any other text control) in a custom cell to change its text font based on the font size in the Setup program, we must:

    1. In the Viewdidload method, register the uicontentsizecategorydidchangenotification notification with the notification hub.

    2. Respond to font change notifications in your code and reset the label's style to correct. For example:

    3. Unregisters the notification in the Viewcontroller Deinit method.

Let's take deliveries as an example to demonstrate.

    1. Opens the Deliveriesviewcontroller.swift file, with the Viewdidload method finally added:

The code above lets the notification hub call the Handledynamictypechange method after the user has changed the dynamic text setting.

    1. Add the following method to the Viewdidload method:

Reload the table View in this method.

    1. Now in Tableview:cellforrowatindexpath: Add code to the last method:

      This code re-sets the font style of the label.

    2. Finally, add the Deinit method below the Viewdidload method:

    3. Let's test the code above. Click the Run button and when the app launches, we'll see that the label text changes to a small font that was previously changed. Press the SHIFT+COMMAND+H key to return to the home screen.

    4. Open the Setup program, enter the General->accessibility->larger text interface, drag the slider to the right, and adjust the font size.

    5. Press the SHIFT+COMMAND+H key to go back to the home screen and cut to the IDELIVERMOBILECD program. We'll see that the label text is getting bigger without restarting the app!

    6. Back to Xcode, terminate the program.

The drawbacks of this approach

This approach has several drawbacks:

    1. We have to set the font two times for each control. Once in the properties panel, once in the code.
    2. We must create a iboutlet for each text control, even if you do not need to use these iboutlet at all.
    3. We have to add the same code to each view controller.

Whenever we need to re-add redundant code in different places, we should consider creating a common workaround to reuse code across all projects.

I've created several classes that make it easier to implement dynamic text in your own projects. Before the test runs, remove the code that we added earlier.

    1. Remove the following code from the Viewdidload method:

    2. Remove the processing method from the Viewdidload method:

    3. Remove the following code from the Tableview:cellforrowatindexpath: method:

    4. Remove the Deinit method located below viewdidload:

A better solution

Now let's look at a better solution.

    1. In the Project Navigator window, right click on Main.storyboard, select Add Files to Idelivermobilecd ....

    2. In the Add File dialog box, uncheck copy items if needed.

    3. In the project folder, select the Mmdynamictypeextensions.swift file, and then click Add. Wait a minute. We're looking at the code, and now we'll look at how to use that code at design time and run time.

    4. In the Project Navigator window, select Main.storyboard. In the deliveries scene, select the heading Label that is located above the cell.

    5. Open the Properties panel, and notice that a new Type observer property is displayed (Figure 18).

      Figure 18–type Observer Properties

      The code that you just added to the project adds a type observer property to the label.

    6. Set the Type Observer property to on.

    7. Select the Subhead tab, and in the Properties panel, set the Type Observer property to on.

    8. All the work is done, let's test it out. Click the Run button, and when the program starts, we'll see the large font text that we set up earlier. Press the SHIFT+COMMAND+H key to return to the home screen.

    9. Open the Setup program and enter the General->accessibility->larger text interface. Drag the slider to the left to reduce the font.

    10. Press Shift+command+h to return to the home screen and cut back to the IDELIVERMOBILECD program. You will see that the label font size has changed!

    11. Return to Xcode and terminate the program.

Processing of dynamic text

Let's take a look at the code.

    1. In the Project Navigator window, open the Mmdynamictypeextension.swift file.

    2. At the top of the file is a protocol that contains only a bool attribute called Typeobserver. This is the property that you set to on in the tag.

    3. After the protocol declaration, a uilabel extension is defined:

      This extension declares the implementation of the Dynamictypechangehandler protocol and implements the Typeobserver property. @IBInspectable property indicates that this property can be displayed in the Properties panel. The setter method for this property invokes the Registercontroler method of the dynamic text manager.

    4. Scrolling down the code, we can see that the Dynamictypemanager object is implemented as a singleton object:

      Singleton mode allows instances of a class to always have only one. When you create an instance of a class, a new instance is created if the class has not yet been instantiated. If the class has already been instantiated, the existing instance object is returned.

      Figure 19 is a sequence diagram that shows the processing logic for dynamic text changes.


      Figure 19– Sequence diagram for dynamic text processing

Here are a few key steps:

    1. When the Typeobserver property is true (through the properties panel), the UI control is registered with the dynamic text manager and a keypath is passed to the control's font properties.

    2. When the first control is registered, the dynamic Type Manager instance is created and begins to register the animated text change notification with the notification hub.

    3. Creates a reference to the control and saves its font style to a nsmaptable. A map table is a dictionary that holds weak references to objects, so that objects saved when key or value is deconstructed are automatically removed. This is just the right thing for us: we don't want to keep strong references to UI controls. When the UI control is released (for example, the user navigates to another view Controller, the current view Contoller is deconstructed), the reference in the nsmaptable (thanks to Big Nerd Ranch sharing this technique) is automatically removed.

    4. When the user changes the font size in the Setup program, the Notification center notifies the Dynamictypemanager object.

    5. The Dynamictypemanager object iterates through the UI controls in the map table, sets their font style for each control, and calls the SizeToFit method.

What are the benefits of this approach?

    • It uses extensions instead of inheritance. So we can use the Uikit component "outside the box".

    • You only need to add mmdynamictypeextension.swift to your project to use it.

    • You no longer need to create iboutlet for UI controls. Just simply set it up in the Properties panel.
    • This approach uses loose coupling. The UI control provides its own properties to the dynamic text manager. This means that you register your custom control (or the new control that Apple will publish in the future) without modifying the dynamic text Manager.

    • You do not need to use this feature on a template cell that is set as the default style, you just have to choose which control to register with the dynamic text manager.

Dynamic text and static text

Let's look at how to use dynamic text in a static cell.

    1. In the Idelivermobiledynamictype project, select the Main.storyboard file to locate the deliveries scene (Figure 20).

      Figure 20–shipment Scene

    2. In the table view of this scene, a dynamic template cell is included as a deliveries scene. The difference is that the shipment scene contains both dynamic text and static text. The blue text (Phone, text, and ID) and status are static. This means that the text is fixed in different invoices. The other text is dynamic, and each invoice is different.

    3. To make these tags also use dynamic text, select each label, and then set the font to any of the iOS font styles in the properties panel, such as:

      Name–headline
      Address Line 1–body
      Address Line 2–subhead
      Phone Labels–body
      Text Labels–body
      Status Labels–body
      ID Labels–body
      IPod Touch Label–body

    4. In the Shipmentviewcontroller.swift file, add the code to the last line of the Viewdidload method:

      Remember that this code tells table view to use an adaptive size cell.

    5. Now let's look at the effect. Click the Run button and when the program starts, select shipment in the Deliveries window to enter the shipment window. We'll see a small font that we've set up earlier in the Setup program.

    6. Now let's look at how the app handles dynamic text changes as the program runs. Switch to the Setup program and select the maximum font. and back to Idelivermobiledynamictypeapp.

As shown in 21, all the static text is gone! This is a bug in iOS itself, and unfortunately it is still unresolved in Xcode6.2. I hope Apple can fix this bug later, but we don't need a custom cell to solve this problem at the moment. We just need to add a bit of code to the Tableview:cellforrowatindexpath: method to reset the static text:

Figure 21-static text is missing!

Another problem is that the first cell is no longer center-aligned. This problem is also added to the same method of code to solve.

    1. In the Tableview:cellforrowatindexpath: method of the file, add the highlighted part of the code:

    2. Click the Run button and when the program starts, go to the shipment page.

3. Cut to the Setup program to set the font to minimum. Back to Idelivermobiledynamictype, we'll find the static text back again (Figure 22)! This is because when the dynamic text font changes, the Reloaddata method of the Table view is automatically called.

Figure 22– Static text is back.

Conclusion

Last year, our company had a booth at the MacWorld Show to showcase my iOS app development book series. A reader with Amblyopia came to the booth and asked me if I could teach developers how to create apps for people with Amblyopia. This led to the creation of this article, I can finally say yes, I hope this article can let you in the face of this problem can also say yes.



Mastering the dynamic text in IOS8

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.