Say goodbye to iOS and common off-screen rendering!

Say goodbye to iOS and common off-screen rendering!

The optimization of mobile applications mainly depends on FPS (page smoothness) performance, memory usage, etc. Off-screen rendering is also a common problem. This article focuses on the common factors that lead to off-screen rendering and their solutions.

So why does off-screen rendering cause performance issues?

In OpenGL, there are two ways of GPU screen rendering: On-Screen Rendering and Off-Screen Rendering. On-Screen rendering does not require the creation of a new cache or the opening of a new context, and has better performance than off-screen rendering. However, due to the limitations of current screen rendering (only its own context, limited screen cache, etc.), off-screen rendering is used when current screen rendering cannot solve some problems. The entire off-screen rendering process requires switching the context environment, first switching from the current screen to the off-screen, and then switching the context environment back after the end. This is why performance is consumed.

[[214033]]

The factors that trigger off-screen rendering include cornerRadius (setting rounded corners), shadows, masks, edge antialiasing, group opacity, shouldRasterize, etc. As for the tool Instruments' Core Animation for detecting off-screen rendering, I won't go into details. This article mainly introduces the solution for setting rounded corners and shadows.

Set rounded corners

Conventional practice:

  1. //You only need to set two properties of the layer
  2. //Set the rounded corners
  3. imageView.layer.cornerRadius = imageView.frame. size .width / 2;
  4. //Cut off the excess
  5. imageView.layer.masksToBounds = YES;

Here are two solutions to avoid off-screen rendering

1. Add a sublayer to the top layer of the view to cover the view and its subviews. Set the layer's image to just cover the required rounded corners, and the image color is exactly the background color of the parent view of the view to achieve the desired effect.

github address

  1. /**
  2. Set a four-corner rounded corner
  3.  
  4. @param radius fillet radius
  5. @param color rounded background color
  6. */
  7. - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color;
  8.  
  9. /**
  10. Set a normal rounded corner
  11.  
  12. @param radius fillet radius
  13. @param color rounded background color
  14. @param corners rounded corner position
  15. */
  16. - (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners;
  17.  
  18. /**
  19. Set a rounded corner with a border
  20.  
  21. @param cornerRadii corner radius cornerRadii
  22. @param color rounded background color
  23. @param corners rounded corner position
  24. @param borderColor border color
  25. @param borderWidth border line width
  26. */
  27. - (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;  

After downloading this category, you can directly drag it into the project to use it. It is very convenient to call. However, when using it, you will find that these three APIs all need to pass a parameter cornerColor (the background color of the parent view), which also causes the limitation of this function. That is, if the color of the parent view is not a solid color, this method is not applicable at this time. Similarly, if the color of the parent view changes, the implementation code is not so elegant, as shown in the figure below, which is a bit embarrassing. Here comes the second solution.


Corner color does not match background color

2. By modifying layer.mask, first create a vector-based path through Bezier curves and pass it to CAShapeLayer for rendering. The path is closed, and then the drawn Shape is assigned to layer.mask. The layer outside the Mask range will not be displayed to achieve a rounded corner effect. The code implementation is very simple, as follows:

  1. UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(130, 330, 100, 100)];
  2. [btn setBackgroundColor:[UIColor colorWithRed:(226.0 / 255.0) green:(113.0 / 255.0) blue:(19.0 / 255.0) alpha:1]];
  3. [backgroundImageView addSubview:btn];
  4. //Draw the curve path
  5. UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:btn.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii: btn.bounds.size ];
  6. CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
  7. //Set the size
  8. maskLayer.frame = btn.bounds;
  9. //Set the graphics appearance
  10. maskLayer.path = maskPath.CGPath;
  11. btn.layer.mask = maskLayer;

Effect picture:


Personally, I think the second solution is simpler and has stronger functional scalability.

Setting up shadows

Conventional practice:

  1. //Shadow color
  2. self.imageView.layer.shadowColor= [UIColorblackColor].CGColor;
  3. // Transparency of the shadow
  4. self.imageView.layer.shadowOpacity=0.8f;
  5. //Shadow rounded corners
  6. self.imageView.layer.shadowRadius=4;
  7. //Shadow offset
  8. self.imageView.layer.shadowOffset=CGSizeMake(0,0);  

Optimization plan:

Avoid modifying shadowOffset directly. Instead, call setShadowPath to provide a CGPath to the view's layer and provide the shape of the rendered View to Core Animation, which will reduce off-screen rendering calculations.

  1. [self.imageView.layer setShadowPath:[[UIBezierPath
  2. bezierPathWithRect:myView.bounds] CGPath]];

Supplement: When the shape of the view using the shadow changes, the shadowPath does not change with the bounds property of CALayer, so after the bounds of the layer change, you need to manually update the shadowPath to make it adapt to the new bounds.

<<:  WeChat ID can be changed at will? Official: It's just a bug

>>:  Are mobile programmers having an easy time in 2017?

Recommend

About Baidu promotion, what is Baidu search promotion?

Baidu search promotion is a pay-per-performance o...

Use vitamin C effervescent tablets with caution, as overdose may cause gout!

Audit expert: Shen Yingjian Director of the Nutri...

Looking back again, the two years stolen by the epidemic

One minute with the doctor, the postures are cons...

National Disability Day丨Today, forward for love!

May 15th is the 32nd National Day for Persons wit...

GITC——Annual gathering of China's Internet technology elites

[[120838]] GITC 2014 Global Internet Technology C...

Top 10 most effective free promotion methods on the Internet in 2015

Introduction: In order to do a good job in online ...

Do you have these 5 smells at home? Strange smells at home are really dangerous!

One minute with the doctor, the postures are cons...

Historical Details (all five volumes)

The Details of History (all five volumes) The whe...