IOS setting rounded corners will cause off screen rendering. Do you really understand?

Time:2021-12-16

1. How to set fillet to trigger off screen rendering

We often see that rounded corners trigger off screen rendering. But in fact, this statement is not accurate, because rounded corners trigger off screen rendering is also conditional!

Let’s take a look at the description of CornerRadius in Apple’s official documents:

Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius 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 be clipped to the rounded corners.

We found the settingscornerRadiusWhen it is greater than 0, it is only the of layerbackgroundColorandborderSet fillet; Not to the layercontentsSet the fillet unless it is also setlayer.masksToBoundsbytrue(corresponding to uiview)clipsToBoundsProperties).

If at this time, you thinklayer.masksToBoundsperhapsclipsToBoundsSet totrueIt triggers off screen rendering, which is not entirely correct.

Let’s first open the off screen rendering color mark of the simulator:

IOS setting rounded corners will cause off screen rendering. Do you really understand?
  • Do not set layer Maskstobounds or clipstobonds. The default value is No
- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
    //Set background color
    view1.backgroundColor = UIColor.redColor;
    //Set border width and color
    view1.layer.borderWidth = 2.0;
    view1.layer.borderColor = UIColor.blackColor.CGColor;
    //Set fillet
    view1.layer.cornerRadius = 100.0;

    view1.center = self.view.center;
    [self.view addSubview:view1];
}
IOS setting rounded corners will cause off screen rendering. Do you really understand?

image.png

When we see only the background color, border and fillet, off screen rendering will not be triggered.

  • set uplayer.masksToBoundsperhapsclipsToBoundsbyYES
- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
    //Set background color
    view1.backgroundColor = UIColor.redColor;
    //Set border width and color
    view1.layer.borderWidth = 2.0;
    view1.layer.borderColor = UIColor.blackColor.CGColor;
    //Set fillet
    view1.layer.cornerRadius = 100.0;

    //Set crop
    view1.clipsToBounds = YES;

    view1.center = self.view.center;
    [self.view addSubview:view1];
}
IOS setting rounded corners will cause off screen rendering. Do you really understand?

When we openlayer.masksToBoundsperhapsclipsToBoundsThe same does not trigger off screen rendering. This is because we haven’t set up the picture yet.

  • set uplayer.masksToBoundsperhapsclipsToBoundsbyYES, and set the picture at the same time
- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
    //Set background color
    view1.backgroundColor = UIColor.redColor;
    //Set border width and color
    view1.layer.borderWidth = 2.0;
    view1.layer.borderColor = UIColor.blackColor.CGColor;

    //Set picture
    view1.layer.contents = (__bridge id)[UIImage imageNamed:@"pkq"].CGImage;

    //Set fillet
    view1.layer.cornerRadius = 100.0;
    //Set crop
    view1.clipsToBounds = YES;
    view1.center = self.view.center;
    [self.view addSubview:view1];
}
IOS setting rounded corners will cause off screen rendering. Do you really understand?

When we openlayer.masksToBoundsperhapsclipsToBoundsWhen the picture is set at the same time, off screen rendering will be triggered.

  • In fact, it’s not just pictures. Adding a sub view with image information such as color, content or border to the view will also trigger off screen rendering.

    There is image informationIt also includes drawing in the drawing method of view or layer.

- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
    //Set background color
    view1.backgroundColor = UIColor.redColor;
    //Set border width and color
    view1.layer.borderWidth = 2.0;
    view1.layer.borderColor = UIColor.blackColor.CGColor;
    //Set fillet
    view1.layer.cornerRadius = 100.0;
    //Set crop
    view1.clipsToBounds = YES;

    //Subview
    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100.0, 100.0)];
    //Any of the following three properties
    //Set background color
    view2.backgroundColor = UIColor.blueColor;
    //Set content
    view2.layer.contents = (__bridge id)([UIImage imageNamed:@"pkq"].CGImage);
    //Set border
    view2.layer.borderWidth = 2.0; 
    view2.layer.borderColor = UIColor.blackColor.CGColor;
    [view1 addSubview:view2];

    view1.center = self.view.center;
    [self.view addSubview:view1];
}
IOS setting rounded corners will cause off screen rendering. Do you really understand?

2. The real reason for off screen rendering triggered by fillet

The overlay drawing of layers probably follows the “painter’s algorithm”.

Oil painting algorithm: draw the objects far away from the observer in the scene first, and then draw the objects close to the observer.

First draw the red part, then draw the ⻩ color part, and finally draw the gray ⾊ part to solve the problem of hidden surface elimination. That is, the scene is sorted according to the physical distance and the distance of the observer, and can be drawn from far to near.

IOS setting rounded corners will cause off screen rendering. Do you really understand?

When we setcornerRadiusas well asmasksToBoundsWhen fillet + clipping,masksToBoundsCrop attributes are applied to all layers.

IOS setting rounded corners will cause off screen rendering. Do you really understand?

Originally, we drew from back to front. After drawing a layer, we can discard it. But now you need toOffscreen BufferSave in and wait for fillet + clipping, which raises theoffscreen rendering

  • Background color, border, background color + border, plus fillet + clipping, according to the document description, becausecontents = nilThere is nothing to crop, somasksToBoundsSet toYESperhapsNONo effect.

  • Once weContent is set for contents, whether it is pictures, drawing contents, sub views with image information, etc., plus fillet + clipping, off screen rendering will be triggered.

    It is not necessary to directly assign values to contents!

3. Ios9 and subsequent optimization

For fillet, IOS 9 and later system versions, Apple has made some optimizations.

  • layer.contents/imageView.image

    We only setcontentsperhapsUIImageViewofimageWith rounded corners and clipping, off screen rendering will not occur. However, if you add background color, border or other layers with image content, it will still produce off screen rendering.

    - (void)viewDidLoad {
        [super viewDidLoad];
        UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
        //Set picture
        view1.layer.contents = (__bridge id)[UIImage imageNamed:@"qiyu"].CGImage;
        //Set fillet
        view1.layer.cornerRadius = 100.0;
        //Set crop
        view1.clipsToBounds = YES;
    
        view1.center = self.view.center;
        [self.view addSubview:view1];
    }
IOS setting rounded corners will cause off screen rendering. Do you really understand?

In fact, this is understandable, because onlymonolayerThe content needs to be rounded and trimmed, so off screen rendering technology is not required. However, if you add a background color, border or other layer with image content, it will be generated asmulti-storeyAdd fillets and cuts, so off screen rendering will still be triggered (as in the third example in 1).

So we’re using something likeUIButtonYou should pay attention to:

  • UIButton

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        //Create a button view
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
        //Set picture
        [button setImage:[UIImage imageNamed:@"pkq"] forState:UIControlStateNormal];
        button.center = self.view.center;
        [self.view addSubview:button];
    }

    We areUIButtonSetting a picture actually adds oneUIImageView

IOS setting rounded corners will cause off screen rendering. Do you really understand?
  • byUIButtonAdding fillets and clipping triggers off screen rendering.

    //Set fillet
    button.layer.cornerRadius = 100.0;
    //Set crop
    button.clipsToBounds = YES;
IOS setting rounded corners will cause off screen rendering. Do you really understand?
  • If changed toUIButtonMediumUIImageViewAdd fillets and clipping, thenOff screen rendering is not triggered

    //Set fillet
    button.imageView.layer.cornerRadius = 100.0;
    //Set crop
    button.imageView.clipsToBounds = YES;
IOS setting rounded corners will cause off screen rendering. Do you really understand?

So we can simply set the fillet

imageView.clipsToBounds = YES;
imageView.layer.cornerRadius = 19.0;