优势和限制
自定义UI提供能更大的绘制灵活性
自定义UI是计算密集型操作,不能充分利用GPU,所以尽可能少的使用本地图形绘制技术。
Depending on the type of app you are creating, it may be possible to use little or no custom drawing code. Although immersive apps typically make extensive use of custom drawing code, utility and productivity apps can often use standard views and controls to display their content.
是否需要自己绘制UI取决于创建的App类型,很可能只需要使用很少或者不使用绘制代码。尽管有一些场景必须使用自定义绘制代码,但是它们的内容通常仍然可以用标准视图和控件显示。
The use of custom drawing code should be limited to situations where the content you display needs to change dynamically. For example, a drawing app typically needs to use custom drawing code to track the user’s drawing commands, and an arcade-style game may need to update the screen constantly to reflect the changing game environment. In those situations, you should choose an appropriate drawing technology and create a custom view class to handle events and update the display appropriately.
在显示需要动态改变的内容时,应该尽可能少的使用自定义绘制代码。这种情况下应该选择合适的绘制技术,并创建一个自定义view用来处理事件和更新显示内容。
On the other hand, if the bulk of your app’s interface is fixed, you can render the interface in advance to one or more image files and display those images at runtime using theUIImageViewclass. You can layer image views with other content as needed to build your interface. You can also use theUILabelclass to display configurable text and include buttons or other controls to provide interactivity. For example, an electronic version of a board game can often be created with little or no custom drawing code.
如果你的app需要显示的内容是固定的,你可以预先将这些内容输入到图像文件并使用UIImageView来显示。
Because custom views are generally more processor-intensive (with less help from the GPU), if you can do what you need to do using standard views, you should always do so. Also, you should make your custom views as small as possible, containing only content that you cannot draw in any other way, use use standard views for everything else. If you need to combine standard UI elements with custom drawing, consider using a Core Animation layer to superimpose a custom view with a standard view so that you draw as little as possible.
因为自定义视图通常是计算密集型操作,(较少的获得GPU的协助),能使用标准视图的情况下尽量使用标准视图。尽可能少的使用自定义视图。如果需要在标准视图上绘制自定义内容,可以考虑使用Core Animation layer叠加在标准视图上面,这样就可以较少的使用自定义绘制代码。
关键概念和理论
For thedrawRect:method, UIKit creates agraphics contextfor rendering to the display. This graphics context contains the information the drawing system needs to perform drawing commands, including attributes such as fill and stroke color, the font, the clipping area, and line width. You can also create and draw into custom graphics context for bitmap images and PDF content.
UIKit创建一个图形上下文(graphics context)用于呈现内容,graphics context包括绘制系统执行绘制命令的信息,包括填充属性、绘制颜色、字体、剪切区域、线宽等等。你也可以在自定义图形上下文创建和绘制位图及PDF。
UIKit has adefault coordinate systemwhere the origin of drawing is at the top-left of a view; positive values extend downward and to the right of that origin. You can change the size, orientation, and position of the default coordinate system relative to the underlying view or window by modifying the current transformation matrix, which maps a view’s coordinate space to the device screen.
UIKit默认的坐标系统,起点是左上角
In iOS, thelogical coordinate space, which measures distances in points, is not equal to the device coordinate space, which measures in pixels. For greater precision, points are expressed in floating-point values.
逻辑坐标空间是以点为单位的,不同于设备以像素为单位的坐标系统。为了更大的精确度,点坐标用浮点数表示。
iOS Drawing Concepts
Important:Not all UIKit classes are thread safe. Be sure to check the documentation before performing drawing-related operations on threads other than your app’s main thread.
The UIKit Graphics System
所有绘制都是在UIView和它的子类中。UIView定义了绘制发生在屏幕的哪一个部分(确定绘制区域)。如果用系统提供的View,绘制区域这个已经自动处理好了。
离屏绘制位图或者PDF上下文时,并不是在一个UIView中绘制,也就意味着关于绘制的部分概念是不适用的,例如The View Drawing Cycle。
The View Drawing Cycle
当view第一次显示或者view的某个区域需要重新绘制时,回调用view的drawRect:方法
以下几种情况会触发view更新:
1、移入/移除一个view遮盖住当前view
2、一个预先隐藏的view,设置器hidden属性为NO
3、把一个离屏的view又回到屏幕
4、在view中显示的调用setNeedsDisplayorsetNeedsDisplayInRect:方法
系统View是自动管理重绘的。
自定义View,需要重写drawRect:方法,并在这个方法内执行所有的绘制代码。
The first time your view becomes visible, iOS passes a rectangle to the view’sdrawRect:method that contains your view’s entire visible area.
当自定义View第一次变得可见时,iOS会发送一个矩形给View的drawRect:方法,这个矩形包括View所有的可见区域。
During subsequent calls, the rectangle includes only the portion of the view that actually needs to be redrawn.
在之后的调用中,这个矩形只包含实际重绘的区域。
如果希望刷新View的内容,调用setNeedsDisplayorsetNeedsDisplayInRect:方法触发重绘。
不要自行调用drawRect:方法,这个方法只能由系统再次绘制的代码自动调用。因为在其他的时候,并不存在图形上下文,所以不能绘制。
Coordinate Systems and Drawing in iOS
The drawing (user) coordinate system. This coordinate system is used when you issue drawing commands.
The view coordinate system (base space). This coordinate system is a fixed coordinate system relative to the view.
The (physical) device coordinate system. This coordinate system represents pixels on the physical screen.
Each view also has acurrent transformation matrix (CTM), a mathematical matrix that maps the points in the current drawing coordinate system to the (fixed) view coordinate system. The app can modify this matrix (as described later) to change the behavior of future drawing operations.
An upper-left-origin coordinate system (ULO),The default coordinate system used by the UIKit and Core Animation frameworks is ULO-based.默认坐标系统
A lower-left-origin coordinate system (LLO),Core Graphics framework is LLO-based
Before calling your view’sdrawRect:method, UIKit establishes the default coordinate system for drawing to the screen by making a graphics context available for drawing operations.
Obtaining Graphics Contexts
Most of the time, graphics contexts are configured for you. Each view object automatically creates a graphics context so that your code can start drawing immediately as soon as your customdrawRect:method is called. As part of this configuration, the underlyingUIViewclass creates a graphics context (aCGContextRefopaque type) for the current drawing environment.
大多数时候,图形上下文已经给你配置好了。每一个UIView对象会自动创建一个图形上下文对象,因此你可以在调用drawRect:后立即开始执行自己的自定义绘制。UIView隐式的为当前绘制环境创建了一个CGContextRef类型的绘制上下文对象。
If you want to draw somewhere other than your view (for example, to capture a series of drawing operations in a PDF or bitmap file), or if you need to call Core Graphics functions that require a context object, you must take additional steps to obtain a graphics context object. The sections below explain how.
如果需要绘制除了当前View以外其他的东西(例如,在位图或者PDF里面获取一系列的绘制操作),或者需要一个上下文对象来调用Core Graphics函数,那么你必须用其他的步骤去获取一个图形上下文对象。
Drawing to the Screen
如果使用Core Graphics函数在UIKit的view中绘制图形,你的绘制操作应该使用ULO坐标系统。
UIGraphicsGetCurrentContext可以获取当前绘制环境的CGContextRef对象。
如果你创建了一个PDF上下文,那么UIGraphicsGetCurrentContext会返回该PDF的CGContextRef对象。如果你要把它绘制到View,必须使用UIGraphicsGetCurrentContext返回的这个CGContextRef对象。
Drawing to Bitmap Contexts and PDF Contexts
Both the bitmap context and the PDF context provided by UIKit establish a ULO default coordinate system.The context that an app directly creates through Core Graphics, however, establishes a LLO default coordinate system.
bitmap上下文和PDF上下文是基于ULO坐标系统的。如果直接用Core Graphics的函数创建一个context,则是基于LLO坐标系统的。
Color and Color Spaces
UIColor对象提供了方便的方法指定颜色,不需要自己指定颜色空间,它已经被UIColor对象自动指定了。
也可以使用CGContextSetRGBStrokeColorandCGContextSetRGBFillColor创建和设置颜色,尽管Core Graphics支持使用其他的颜色空间创建颜色或者自定义颜色空间,但不推荐在自定义绘制代码中使用,自定义绘制应该一直使用RGB色彩空间。
Configuring the Graphics Context
上下文状态可以保存,使用CGContextSaveGState保存一个上下文状态,将状态推入堆中。接下来对上下文状态的操作不会影响保存到堆中的上下文状态。当需要恢复到之前的上下文状态时,可以使用CGContextRestoreGState恢复。这样在不同的上下文状态之间切换就不用重复执行配置代码。
Customizing the Coordinate Space
you can change the CTM by adding scaling, rotation, and translation factors to it and thereby change the size, orientation, and position of the default coordinate system relative to the underlying view or window.
Using Coordinate Transforms to Improve Drawing Performance