IOS efficient add fillet effect in combat

Source: Internet
Author: User
Tags uikit

Rounded Corners (Roundercorner) are a very common view effect, which is softer and more acceptable than the right angle. But many people do not know how to set the correct way and the principle of fillet. Setting the fillet can lead to some performance loss, and how to improve performance is another topic to focus on. I looked up some of the available information and learned a lot and found some misleading mistakes. This paper summarizes some of the knowledge points, summarized as follows:
    • Correct posture and principle of setting rounded corners
    • Set the performance loss of the Fillet
    • Other ways to set rounded corners, and the best choice

I made a demo for this article, and the reader can clone it on my github: Cornerradius, if it feels helpful, look for a star to show support. The project is implemented by Swift, but be sure to believe me even if you only objective-c, you can read it. Because the key knowledge is not related to Swift.

Correct posture

The first thing I want to declare is:

Setting the fillet is simple, it does not result in any performance loss

Because this is a simple thing, it only needs a single line of code:

5

Don't hurry to turn off the webpage, also don't hurry to reply, we let the fact speak. Open instuments, select Core Animation Debug, and you will find neither off-screen Render nor decrease frame count. For the use of instuments analysis applications, you can refer to my article: Uikit Performance Tuning combat. From there you can see that the third Brown view is actually set with a rounded corner:


Fillet effect

But looking at the code, you can see that one of UILabel them also has rounded corners, but it doesn't show any change. For this, you can view cornerRadius the comment for the property:

By default, the corner radius does does not apply to the image in the layer's contents property; It applies only to the background color and border of the layer. However, setting the Maskstobounds property to true causes the content to being clipped to the rounded corners.

This means that by default, this property only affects the background color and border of the view. There's UILabel nothing you can do about a control that has a child view inside. So in many cases we will see this code:

5label.layer.masksToBounds = true

We add the second line of code to CustomTableViewCell the construction method, run Instument again, you can see the fillet effect.

Performance loss

If you tick the color offscreen-rendered Yellow, you will notice a yellow mark around the label, indicating that there is an off-screen rendering. The introduction of off-screen rendering, the same can be consulted: Uikit performance tuning in combat, it is not covered in this article.

It is important to emphasize that off-screen rendering is not caused by the setting of rounded corners! It is easy to draw this conclusion by controlling the variable, because the UIView is only set cornerRadius , but it does not appear off-screen rendering. Some of the more authoritative articles, such as StackOverflow and Codereview, mention that setting cornerRadius causes off-screen rendering to affect performance, and I think this is really wrong with the cute cornerRadius variables and misleading others.

Although settings masksToBounds can result in off-screen rendering, which can affect performance, how big is this effect? On my iPhone6, even if there are 17 views with rounded corners, the number of frames sliding is still fluctuating around 58-59 fps.

However, this is not an indication of what special optimizations are made for IOS 9, or the impact of off-screen rendering, mainly due to the lack of rounded corners . When I set a UIImageView rounded corner, that is, the rounded view on the screen reached 34, the FPS dropped sharply, about 33 or so. Has basically reached the scope that affects the user experience. Therefore, all do not tell the basis of the optimization are bullying, if you are not many corner view, cell is not complex, do not bother to toss.

Set rounded corners efficiently

Assuming there are a lot of rounded views (for example, in Uicollectionview), how do you add rounded corners efficiently for the view? Most of the online tutorials do not say the whole, because this matter should be divided into two situations. The general UIView setting of fillets is very different from the principle of setting the UIImageView rounded corners.

One way to do this is to try to achieve cornerRadius = 3 the effect of this notation:

override func drawRect(rect: CGRect) { let maskPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: 3, height: 3)) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = maskPath.CGPath self.layer.mask = maskLayer}

But this is a wrong way of writing!

First, we should try to avoid rewriting the drawRect method. Improper use of this method can result in a burst of memory. For example, iPhone6 on the screen with large UIView , even if rewriting an empty drawRect method, it also occupies at least 750 * 1134 * 4 字节 ≈ 3.4 Mb the memory. In Memory Goblin DrawRect and its follow-up, the author describes in detail the principle, according to his Test, in IPhone6, and the screen and other large view rewriting drawRect method will consume 5.2 Mb of memory. In short, avoid rewriting the drawRect method as much as possible.

Second, this approach is essentially implemented with a mask layer mask , so the same unavoidable results in off-screen rendering. I try to use the previous 34 views of the fillet to this method, the result of FPS dropped to about 11. Already belong to the rhythm of the card-xiang.

Forget about the way it is written, and here's how to set the rounded position efficiently.

Add rounded corners to UIView

The principle of this approach is to draw rounded corners manually. Although as we have said before, it is possible to set properties directly for normal views cornerRadius . But in case of unavoidable need to use masksToBounds , you can use the following method, its core code is as follows:

FuncKt_drawrectwithroundedcorner(Radius radius:cgfloat, borderwidth:cgfloat, Backgroun  Dcolor:uicolor, Bordercolor:uicolor)uiimage {uigraphicsbeginimagecontextwithoptions (SizeToFit, false, uiscreen.mainscreen (). Scale) let context = uigraphicsgetcurrentcontext () cgcontextmovetopoint ( Context, starting position); //start coordinates right start cgcontextaddarctopoint (context, x1, y1, x2, y2, radius ); //This type of code repeats four times cgcontextdrawpath ( Uigraphicsgetcurrentcontext (),. fillstroke) let output = uigraphicsgetimagefromcurrentimagecontext (); uigraphicsendimagecontext (); return output}            

This method returns UIImage , meaning that we draw a rounded rectangle ourselves with the Core Graphics. In addition to some of the necessary code, the core is the CGContextAddArcToPoint function. The four parameters in the middle represent the start and end coordinates of the curve, and the last parameter represents the radius. Once you have called four functions, you can draw a rounded rectangle. Finally, the picture is retrieved from the current drawing context and returned.

With this picture, we create one UIImageView and insert it at the bottom of the view level:

extension UIView {    func kt_addCorner(radius radius: CGFloat, borderWidth: CGFloat, backgroundColor: UIColor, borderColor: UIColor) { let imageView = UIImageView(image: kt_drawRectWithRoundedCorner(radius: radius, borderWidth: borderWidth, backgroundColor: backgroundColor, borderColor: borderColor)) self.insertSubview(imageView, atIndex: 0) }}

The complete code can be found in the project, and when used, you only need to write this:

let view = UIView(frame: CGRectMake(1,2,3,4))view.kt_addCorner(radius: 6)
Add rounded corners to Uiimageview

Compared to one of the above implementations, it is UIImageView more common to add rounded corners. The idea of its realization is to capture the image directly:

ExtensionUIImage {FuncKt_drawrectwithroundedcorner(Radius radius:cgfloat,_ Sizetofit:cgsize)UIImage {Let rect =CGRect (Origin:Cgpoint (x:0, Y:0), Size:sizetofit)Uigraphicsbeginimagecontextwithoptions (Rect.size,FalseUiscreen.mainscreen (). Scale)cgcontextaddpath (uigraphicsgetcurrentcontext (), uibezierpath (Roundedrect:rect, byroundingcorners: UIRectCorner.< Span class= "Hljs-type" >allcorners, cornerradii: cgsize (Width:radius, Height:radius)). cgpath) cgcontextclip ( Uigraphicsgetcurrentcontext ()) self.drawinrect (rect)  Cgcontextdrawpath (uigraphicsgetcurrentcontext (),.  Fillstroke) let output =  Uigraphicsgetimagefromcurrentimagecontext (); uigraphicsendimagecontext (); return Output}}            

The fillet path is plotted directly with Bezier curves, and an unexpected bonus is the choice of which corners have rounded corners. The effect of this function is to cut the original into UIImage rounded corners. With this function, we can expand a method for Uiimageview to set the fillet:

extension UIImageView {    /**     / !!!只有当 imageView 不为nil 时,调用此方法才有效果     :param: radius 圆角半径     */    override func kt_addCorner(radius radius: CGFloat) { self.image = self.image?.kt_drawRectWithRoundedCorner(radius: radius, self.bounds.size) }}

The complete code can be found in the project, and when used, you only need to write this:

let imageView = let imgView1 = UIImageView(image: UIImage(name: ""))imageView.kt_addCorner(radius: 6)
Remind

Regardless of which method you use, you need to be careful with the background color. Because we don't have the settings at this point masksToBounds , the part that goes beyond the fillet will still be displayed. Therefore, you should not use the background color again, you can set the fill color when the rounded rectangle is drawn to achieve a similar effect.

UIImageViewwhen you add a fillet, make sure that the image property is not nil , or the setting will be invalid.

Real-Combat testing

Back in the demo, test the two methods that you just defined to set the fillet. First, uncomment the setupContent two lines of code in the method:

5)imgView2.kt_addCorner(radius: 5)

Then use a custom method to set the fillet for label and view:

6)label.kt_addCorner(radius: 6)

Now, we have not only successfully added the fillet effect, but also ensured that the performance is not affected:


Performance testingOriginal address: Http://www.jianshu.com/p/f970872fdc22

Reference: 1, be careful not to make the rounded corners the number of frames in your list killer http://www.cocoachina.com/ios/20150803/12873.html ()

2, about the performance of some problems http://www.reviewcode.cn/article.html?reviewId=7

Summarize
      1. If you can only cornerRadius solve the problem, you do not have to optimize.
      2. If you have to set up masksToBounds , you can refer to the number of rounded views, and if the number is small (only a few pages), you can consider not optimizing.
      3. UIImageViewRounded corners are achieved by directly intercepting the image, and the corners of other views can be achieved by drawing a rounded rectangle from the Core Graphics.

IOS efficient add fillet effect in combat

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.