Design for iOS: graphics and performance

Source: Internet
Author: User
Tags uikit

In the previous article, we explored the UIButton of customizing based on a variety of different technologies, but the complexity and difficulty of the code involved are different. But I also intentionally mentioned that the performance of the implementations based on different approaches is not the same.

"Something behind the screen."

To understand how performance is affected, we need to look further at some of the things behind the graphics implementation in iOS. The following diagram shows some of the links between the different frameworks and libraries:

On top of that is Uikit, a OBJC advanced framework for managing user graphics interactions in iOS, consisting of a series of collection classes, such as UIButton, UILabel, each responsible for the UI control role they specify. The Uikit itself is built on a framework called Core animation, which is known for introducing OS X Leopard and iOS because it is used to handle a more powerful smooth transition effect.

A bit further down is OpenGL ES, a standard open source library for drawing 3D computer graphics on mobile devices, which is widely used in the graphics of games, and also plays a powerful role in core animation and Uikit.

The final part is the core Graphics, which was introduced in quartz (a CPU-based drawing engine that was first seen on OS X systems). These two lower-level frameworks are written in the C language.

The bottom line in is the hardware layer, which consists of the GPU and CPU.

What we often say about hardware acceleration is the fact that Opengl,core Animation/uikit is based on the GPU's implementation of computer graphics compositing and drawing, and so far the hardware acceleration on iOS is still significantly ahead of Android, which relies on CPU drawing, The vast majority of animation implementations will make people feel obvious lag.

Off-screen drawing (offscreen drawing) refers to the GPU while drawing on the current screen, while the other side of the screen has not processed the image information through the CPU to generate image information processing process. In iOS, the off-screen drawing is triggered automatically when the following is the case:

* Core Graphics (any class that starts with CG)

* In the DrawRect method, even the empty method is implemented

* All Shouldrasterize properties are calayers objects with Yes

* All Calayers objects with masks (setmaskstobounds) and dynamic Shadows (setshadow*)

* All text is drawn, including Coretext

* Group opacity (uiviewgroupopacity)

In general, when it comes to animation, the off-screen drawing affects performance, and you can perform a real-machine debug with instruments to detect which part of the UI is being drawn off-screen:

1. Access devices

2. Open Instruments (command+shift+i) in Xcode's developer applications

3. Select Ios>graphics>core Animation Template

4. Open the Details panel and select the appropriate window mode

5. Select your target device

6. Check the debug options for color offscreen-rendered yellow

7. All off-screen drawing on your device will show a yellow hue

Now let's examine the performance of some of the technical points covered in the previous article.

"Pre-resource loading drawing"

Using UIImage to load a picture originally on disk as a background image of a custom UIButton is entirely dependent on drawing with the GPU. And if you use a resizable picture, it is also appropriate to avoid when the background size of the dynamic transformation of the need for different size of the picture, so that we can make the app's bundle smaller, and in the drawing of the picture of the pixel also repeated use of hardware acceleration.

"Using Calayer"

Because we used the mask to draw the rounded corners based on the Calayer implementation method, this involves drawing off-screen. When we use the Core animation framework, we must explicitly prohibit the use of animated effects if the above-mentioned properties for drawing fillets are turned on. As a bottom line, this method does not work unless you want to have an animated transition effect.

"Using DrawRect"

The DrawRect method relies on the core graphics framework for custom drawing, but the main drawback of this approach is the way it handles touch events: Each time the button is clicked, it is forced to redraw with Setneddsdisplay, and more than once, Each single point event triggers two executions. In this case, from a performance standpoint, the CPU and memory are poor. Especially if there are multiple instances of such uibutton on our interface.

"Skill mix hybrid approach"

In this case, does it mean that drawing using pre-resource loading is the only viable option? The answer is in the negative. If you insist on the flexibility of drawing with code, there are some optimizations and techniques to reduce the performance cost. One possible solution is to create a stretchable bitmap and reuse it across multiple instance objects.

We follow the same steps in the previous tutorial to create a new UIButton subclass, and then define some static variables as follows

    1. #import "CBHybrid.h"
    2. @implementation Cbhybrid
    3. static int borderradius = 5;
    4. static int height = 37;

Next we change the code in the Cbbezie inside the DrawRect, after a series of changes: we can create a resizable image to replace the previously fixed-size image, and then we can hold the static object and make it easy to reuse

    1. -(UIImage *) drawbackgroundimagehighlighted: (BOOL) highlighted {
    2. }

First, we need to know the width of our resizable image, in order to optimize performance, we should keep a pixel width in the middle of the picture.

    1. Float width = 1 + (Borderradius * 2);

High is not very important in this case, because the height of the button is sufficiently visible to the gradient layer and is set to 37pt for the same reason as the other buttons.

When we do, we need a bitmap context to draw, to get up ~

    1. Uigraphicsbeginimagecontextwithoptions (Cgsizemake (width, height), NO, 0.0);
    2. Cgcontextref context = Uigraphicsgetcurrentcontext ();
    3. Cgcolorspaceref colorspace = Cgcolorspacecreatedevicergb ();

Uigraphicsbeginimagecontextwithoptions The second argument is no, make sure that the image context we created is transparent (with Alpha) and that the last parameter is scale factor (screen density), If it is 0, it is the default scale factor for the current device.

The next code is very similar to the demo we used to implement cbbezier with the core graphics. We replace the default Self.highlighted property with the highlighted parameter, saving the information value of the image used as the update interface.

    1. Uibezierpath *roundedrectanglepath = [Uibezierpath bezierpathwithroundedrect:cgrectmake (0, 0, width, height) Cornerradius:borderradius];
    2. [Roundedrectanglepath Addclip];
    3. Cggradientref background = highlighted? Highlightedgradient:gradient;
    4. Cgcontextdrawlineargradient (context, background, cgpointmake (0), Cgpointmake (height-1), 0);

The only step we need to add is to use Uigraphicsendimagecontext to save the image information and put it in the UIImage object.

    1. uiimage* backgroundimage = Uigraphicsgetimagefromcurrentimagecontext ();
    2. Uigraphicsendimagecontext ();

Now that we have finished creating the background image, we have to implement a generic initialization method to instantiate the images and set them as the real background of the Cbhybird instance.

  1. -(void) Setupbackgrounds {
  2. if (!gbackgroundimage &&!gbackgroundimagehighlighted) {
  3. Gbackgroundimage = [[Self drawbackgroundimagehighlighted:no] Resizableimagewithcapinsets:uiedgeinsetsmake ( Borderradius, Borderradius, Borderradius, Borderradius) Resizingmode:uiimageresizingmodestretch];
  4. gbackgroundimagehighlighted = [[Self drawbackgroundimagehighlighted:yes] Resizableimagewithcapinsets: Uiedgeinsetsmake (Borderradius, Borderradius, Borderradius, Borderradius) Resizingmode:uiimageresizingmodestretch];
  5. }
  6. [Self setbackgroundimage:gbackgroundimage forstate:uicontrolstatenormal];
  7. [Self setbackgroundimage:gbackgroundimagehighlighted forstate:uicontrolstatehighlighted];
  8. }

We can use the custom type to instantiate our Cbhybird, of course, we can use the Initwithcoder, if we want to implement in the code, we can also use the initWithFrame (... Actually here I do not want to translate, the original author is really too detailed, the first translation of technical articles, or thoroughly point it ... )

    1. + (Cbhybrid *) Buttonwithtype: (uibuttontype) type
    2. {
    3. return [Super Buttonwithtype:uibuttontypecustom];
    4. }
    5. -(ID) Initwithcoder: (Nscoder *) Adecoder {
    6. self = [super Initwithcoder:adecoder];
    7. if (self) {
    8. [Self setupbackgrounds];
    9. }
    10. return self;
    11. }

In order to ensure that our new Bhybird class can be used normally, in Interface Builder we assign a button, change the implementation class to Cbhybird, then change the content of the button to cgcontext-generated Image (easy to distinguish). The donkey is a horse, we cmd+r run up and try.

The complete subclass implementation code is here ~ ~ ~

Conclusion

When all is done, we find that loading drawing with a pre-resource is still better than any code-based implementation. However, Core Graphicsis has the advantage of efficiency and flexibility. Therefore, the hybrid scheme based on the two techniques now appears to contain the above two strengths and has no noticeable effect on performance.

Cocoachina is the world's largest Apple development Chinese community, the official daily regularly push a variety of exciting research and development resources and tools, the introduction of app marketing experience, the latest corporate recruitment and outsourcing information, as well as the cocos2d engine, Cocostudio Development Toolkit, the latest news and training information. Attention can be the first time to understand the latest product and service dynamics, in hand, the world I have!

Design for iOS: graphics and performance

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.