iOS UI drawing principle

High-quality graphics play a very important role in an app's interface. The high-quality graphics display makes it more enjoyable for users to use it. The iOS system mainly provides two ways to create high-quality graphics: OpenGL or using native Quarts, Core Animation and UIKit. This article will expand on the latter.

Quartz is the main drawing approach, which provides the ability to create presentation and parsing based on path drawing, antialiasing drawing, gradient color, graphic drawing, color, deformation and PDF documents. UIKit is an encapsulation of Quartz's line, image and color operations. Core Animation provides support for modifying UIView properties during animations, as well as implementing custom animations.

This chapter will describe the rendering process in iOS App and explain the drawing principles used in it. It can help you learn some tips to optimize rendering for your own app.

Important: Not all UIKit classes are not thread-safe. Please make sure that you are on the main thread when executing the drawing.

UIKit graphics system

In iOS, whatever technology (OpenGL, Quartz, UIKit, or Core Animation) is used to draw in a UIView or a subclass, is displayed on the screen. A view defines how it draws on the screen, or how it presents itself. System-provided views automatically define their own presentation. To customize a view you must define how the view is presented. This chapter explains how to draw custom graphics with Quartz, Core Animation, and UIKit.

In addition, bitmaps and PDF graphics contexts can be drawn off-screen. When you draw offscreen, the view's lifecycle doesn't work for that either, since there's no drawing on the view.

View life cycle

Subclasses of UIView contain the most basic graphics drawing model -- updating and drawing itself as needed. The UIView class makes updating the drawing itself simple and efficient by updating the drawing in batches and updating the drawing itself at the right time.

drawRect:The iOS system always asks for methods when a view or part of a view needs to be updated for the first time .

Here are some actions that trigger view updates:

  • Move or delete views
  • By setting the view's hiddenproperty toNO
  • Views that disappear on scroll need to appear on screen again
  • View explicit call setNeedsDisplayor setNeedsDisplayInRect:method

The view system automatically triggers a repaint. For custom views, it is necessary to override the drawRect:method to perform all the drawing. Use the native drawing API in the method to draw its own shape, text, image, gradient or whatever you want to display. When the view is displayed for the first time, the iOS system will pass a square area to represent the area where the view is drawn. In order to maximize performance, it is best to redraw only the affected part when redrawing .

After calling the drawRect:method, the view marks itself as updated and waits for the next view update to be triggered. Static custom views need to handle view changes that appear because of scrolling or because other views appear. (Translator Tucao: What does the second half of the sentence mean? I don’t quite understand)

If you want to change the content of the view, you must trigger the view to redraw the content. Updates are triggered by calls setNeedsDisplayor setNeedsDisplayInRect:methods. Use scenarios such as updating the view multiple times a second, or appearing new content in the view based on user interaction.

drawRect:Important: Do not call methods explicitly . This method should only be reserved for system calls when iOS needs to repaint. Because the graphics context does not exist at other times, it cannot be drawn to the screen. (Graphics context is explained in the next subsection.)

Coordinate system and drawing in iOS

When an App needs to draw graphics in the iOS system, it must be drawn in a two-dimensional coordinate system. This seems simple, but in some drawing situations it is necessary to deal with a different coordinate system.

Graphics drawing in iOS needs to rely on the graphics context to complete. In theory, the graphics context is used to describe where and how to draw, including information such as color drawing, cutting drawing area, line thickness and style.

Additionally, Figure 1-1 shows that each graphics context has a coordinate system. More precisely, each figure has three coordinate systems up and down:

  • Draw the coordinate system. The drawing context draws the coordinates by using the directive.
  • View coordinate system. A fixed coordinate system relative to the view.
  • Device coordinate system. The pixel display coordinates of the physical screen.

Figure 1-1 The relationship between drawing coordinates, view coordinates and hardware coordinates

Picture 1-1

Translator's Note: CTM is a concept in Quartz, which will be introduced below.

iOS's drawing framework creates graphics contexts for drawing to a specific target (screen, bitmap, PDF content, etc.), and these graphics contexts establish the initial drawing coordinate system for that destination. This initial coordinate system is called the default coordinate system and is 1:1 mapped to the view coordinate system. (Translator complains: I don't understand the second half of the sentence)

Each view has its own current transformation matrix(CTM), a numeric proof that maps the current drawing coordinate system to the view coordinate system. Apps can modify the matrix to affect subsequent drawing operations.

iOS creates a graphics context based on the default coordinate system. There are two main types in iOS:

  • The upper left origin coordinate system (ULO), which is 0,0 coordinates from the upper left corner, positive to the right and down, both UIKit and Core Animation are based on ULO.
  • The lower left origin coordinate system (LLO), which is 0,0 coordinates from the lower left corner, positive to the right and up, Core Graphics is based on LLO.

The two coordinate systems are shown in Figure 1-2

Figure 1-2 Default coordinate system in iOS

Figure 1-2

Tip: MacOS uses LLO by default. Drawing through AppKit and CoreGraphics is based on this coordinate system, and AppKit provides conversion support for the upper left origin coordinate system.

dots and pixels

There is a difference between the coordinate system specified in the iOS system and the pixel the underlying device draws. When using native drawing programs such as Quartz, UIKit and Core Animation, both the drawing coordinate system and the drawing coordinate system are logical coordinate systems. Values ​​represent points , and do not have a one-to-one correspondence with pixels on the device.

The system will automatically map to the pixel of the device according to the point coordinate value of the view, but it is not necessarily a one-to-one mapping, which is very important.

A point does not necessarily map to a physical pixel.

The main purpose of using pixels instead of dots is to make the view appear in the right size on the device, so that the original view will not become smaller because the screen pixel becomes higher. The specific number of pixels corresponding to a point is determined by the system according to the current device hardware. For example, on a retina screen, a line is drawn corresponding to a line width of pixels. This mapping relationship makes the size of the display view on the normal screen retina screen and the higher resolution screen basically the same.

Tip: A dot corresponds to 1/72 of an inch when rendering and printing PDFs in Core Graphics.

In iOS, UIScreen, UIView, UIImage and CALayer all provide properties for describing the mapping ratio between pixels and points. For example, UIKit's View contentScaleFactorproperties. On non-retina screens, the value of this property is 1.0. In the retina screen, it is 2.0 (Translator's Note: There should be 3.0 after the plus series). Other values ​​may also appear in the future. (1.0 until iOS4).

Because of the automatic mapping, you don't need to care about pixels when drawing the view. Only when downloading high-resolution images to display on the retina screen, you need to care about the scale of the image rendering to avoid the problem of high-resolution images being rendered larger by low-resolution images.

In iOS, when you draw something on the screen, the graphics subsystem uses a technique called antialiasing to approximate a high-resolution image on a low-resolution screen. Explain with an example. Draw a black vertical line on a white background. If the line falls exactly on the pixel, it will appear as a series of black pixels arranged on the left side of the image below. If it falls exactly on two pixels, there will be gray pixels drawn on the right side of Figure 1-3.

Figure 1-3

Integer-valued point coordinates fall in the middle of two pixels. For example, drawing a line (1,1) to (1,10) with a width of 1 pixel will result in a gray line. If you draw a line that is two pixels wide, you will get a solid black line because two pixels fall exactly over two pixels. In general, lines that are odd-numbered physical pixels wide appear lighter compared to the width of even-numbered physical pixels if they are not repositioned so that they completely cover the pixel.

The scale attribute is to indicate how many pixels a point is mapped to.

On non-retina screens, the scale is always 1.0, and a point corresponds to a pixel. To avoid anti-aliasing, when you draw a single-point line, if it occupies an odd integer width, you need to offset it by 0.5 points, if it occupies an even width, you don't have to.

Figure 1-4 Display of a dot-width line on non-retina and retina screens

At a retina scale of 2.0, a single line will not trigger anti-aliasing, because it will fill two pixels. To draw a one-pixel line, use a width of 0.5 points and an offset of 0.25 points.

Controlling pixel drawing directly according to scale does not give the best experience. A one-pixel wide line might look fine on a non-Retina screen, but it would look too thin on a retina screen. It depends on how you are going to draw.

get image context

The image context can be obtained in the drawRect:method and drawn immediately. UIView provides a drawing environment for the image context.

If you want to draw outside of the view (for example, to capture a sequence of drawing operations in a PDF or bitmap file), or if you need to call core graphics functions that require a context object, then you must take extra steps to get the graphics context object. The following sections explain why.

Refer to [ Quartz 2D Programming Guide ] for more information on modifying image context state and creating custom content. For the method list of image context, please refer to [ CGContext Reference ], [ CGBitmapContext Reference ], [ CGPDFContext Reference ]

draw on the screen

To draw on the screen, you need drawRect:to get the image context in the method. (The first parameter in this series of methods is an CGContextRefobject.) You can obtain a graphics context in a method by calling UIGraphicsGetCurrtnContextthe method . drawRect:(Multiple fetches will also get the same one.)

In UIKit views, drawing using the Core Graphics family of methods is based on the ULO coordinate system. Alternatively, flip the CTM to draw using the LLO coordinate system. For details, please read [ Flipping the Default Coordinate System ]

The UIGraphicsGetCurrentContext function always returns the current context. For example, the context obtained after creating a PDF is the PDF context. As long as you use the Core Graphics series of functions to draw, you must use this method to obtain the context.

Tip: Printing related functions are placed in the UIPrintPageRenderclass. Similarly drawRect:, UIKit provides printing related implementations in it. And the default is also based on the ULO coordinate system.

Drawing bitmaps and PDFs

UIKit provides context and series functions for drawing bitmaps and PDFs. Both creation methods need to call a function to create its corresponding context. Draws through the context, and closes the context when the drawing is complete.

Both contexts are also based on the ULO coordinate system. Core Graphics provides a series of methods for drawing in the context of bitmaps and in the context of PDFs. The context is obtained by calling functions directly in Core Graphics and is drawn based on the LLO coordinate system.

**Tip:** In iOS, it is still recommended to use the related functions of UIKit to obtain the context for drawing. If you have to use the related methods in Core Graphics to draw, you need to be compatible with the difference in coordinate systems. (Translator: So the context-sensitive methods in UIKit are actually Core Graphics methods that transform the coordinate system.)

For details, please refer to Create Drawing Bitmap and Create PDF

Color and gamut

Although Quartz supports the full color gamut on iOS; almost all apps only use the RGB color gamut. After all iOS is designed to draw and render on the screen, and RGB is the best fit.

The UIColor object provides a series of convenient methods to create colors from RGB/HSB and grayscale color values, and does not need to care about the color gamut problem, but is determined automatically by the UIColor object.

Set colors can also be created using the CGContextSetRGBStrokeColorsum functions in the Core Graphics framework . CGContextSetRGBFillColorAlthough Core Graphics provides functions to specify color gamuts and create custom color gamuts, their use in code is not recommended. (Translator: Why not recommend? Why?) It is still recommended to always use the RGB color gamut.

Drawing with Quartz and UIKit

We collectively refer to the drawing technology in iOS as Quartz. The Core Graphics framework is the heart of Quartz and does most of the drawing stuff. The framework provides data types and functions to support the following capabilities:

  • graphics context
  • path
  • Pictures and Bitmaps
  • transparent layer
  • Color and gamut
  • Gradients and Shadows
  • font
  • PDF

UIKit provides a set of classes related to graphics operations on the basis of Quartz. The intent is not to replace Core Graphics, instead, they are meant to provide drawing support to other UIKit classes:

  • UIImage/UIColor/UIFont/UIScreen/UIBezierPath
  • Function to generate a JPEG or PNG image object
  • Function to get bitmap context
  • Function to get PDF context
  • Functions to draw rectangles and crop the drawing area
  • Function to get the current graphics context

For more information, see UIKit Framework Reference , and Core Graphics Reference .

Configure graphics context

Before calling the drawRect:method , the view object has created a graphics context and made it the current context. It only exists during drawRect:method invocation. UIGraphicsGetCurrentContextA reference to the graphics context can be obtained by calling the function. The method returns a CGContextRefreference to an object of type that passes the Core Graphics function to modify the state of the current graphics. Table 1-1 lists the main methods. To view the complete please go to CGContext Reference . The table below also lists UIKit alternatives.

Table 1-1 Core Graphics methods for modifying graphics state

condition Function name UIKit Alternative
Current transformation matrix (CTM) CGContextRotateCTM/CGContextScaleCTM/CGContextTranslateCTM/CGContextConcatCTM None
Clipping area CGContextClipToRect UIRectClip function
Line: Width, join, cap, dash, miter limit CGContextSetLineWidth/CGContextSetLineJoin/CGContextSetLineCap/CGContextSetLineDash/CGContextSetMiterLimit None
Accuracy of curve estimation CGContextSetFlatness None
Anti-aliasing setting CGContextSetAllowsAntialiasing None
Color: Fill and stroke settings CGContextSetRGBFillColor/CGContextSetRGBStrokeColor UIColor class
Alpha global value (transparency) CGContextSetAlpha None
Rendering intent CGContextSetRenderingIntent None
Color space: Fill and stroke settings CGContextSetFillColorSpace/CGContextSetStrokeColorSpace UIColor class
Text: Font, font size, character spacing, text drawing mode CGContextSetFont/CGContextSetFontSize/CGContextSetCharacterSpacing UIFont class
Blend mode CGContextSetBlendMode The UIImage class and various drawing functions let you specify which blend mode to use.

The loading of the graph is stored in the context as a stack. The stack is empty when the context is created by Quartz. CGContextSaveGStatePushes the current graphics state onto the stack by calling a function. Subsequent changes to the graphics state will affect subsequent drawing operations, but will not affect the previous stack. When the modification is completed, it can be CGContextRestoreGStatepopped from the stack by calling the function. This push and pop operation replaces the operation of undoing each state one by one. This is also the only way to restore to the previous state.

For more information see Graphics Context and Quartz 2D

draw path

A path is a vector shape composed of a series of lines and bezier curves. UIKit includes functions such as UIRectFrameand UIRectFillfor drawing simple paths (like rectangles). Core Graphics also provides convenience functions for drawing simple paths (such as rectangles and ellipses).

For more complex paths, you need to use UIBezierPathclasses to draw them yourself, or use functions to operate provided by Core Graphics CGPathRef. Although the path can be drawn out of context, the bottom layer still uses the context, it's just encapsulated.

--- end---

Original: iOS Drawing Concepts

Further reading

CTM

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325340353&siteId=291194637