Drawing mask influence performance

2019-06-09 19:43发布

问题:

Here is a code I use for drawing mask for UIView. The problem is that if I have more than 5 UIViews with mask on the screen it influence performance when drag & drop UIViews: How can I improve the code below?:

+ (UIBezierPath *)roundedPathAtCenter:(CGPoint)center size:(CGSize)size corner:(CGFloat)corner
{
    NSInteger width = size.width;
    NSInteger height = size.height;

    UIBezierPath *path = [UIBezierPath bezierPath];

    // upper left corner
    [path moveToPoint: CGPointMake(center.x - width / 2.0f + corner / 2.0f, center.y - height / 2.0f + corner / 2.0f)];

    // path to top center
    [path addQuadCurveToPoint: CGPointMake(center.x, center.y - height / 2.0f) controlPoint: CGPointMake(center.x - width / 2.0f + corner, center.y - height / 2.0f)];

    // path to upper right
    [path addQuadCurveToPoint: CGPointMake(center.x + width / 2.0f - corner / 2.0f, center.y - height / 2.0f + corner / 2.0f) controlPoint: CGPointMake(center.x + width / 2.0f - corner, center.y - height / 2.0f)];

    // path to mid right
    [path addQuadCurveToPoint: CGPointMake(center.x + width / 2.0f, center.y) controlPoint: CGPointMake(center.x + width / 2.0f, center.y - height / 2.0 + corner)];

    // path to lower right
    [path addQuadCurveToPoint: CGPointMake(center.x + width / 2.0 - corner / 2.0f, center.y + height / 2.0f - corner / 2.0f) controlPoint: CGPointMake(center.x + width / 2.0f, center.y + height / 2.0f - corner)];

    // path to center bottom
    [path addQuadCurveToPoint: CGPointMake(center.x, center.y + height / 2.0f) controlPoint: CGPointMake(center.x + width / 2.0 - corner, center.y + height / 2.0)];

    // path to lower left
    [path addQuadCurveToPoint: CGPointMake(center.x - width / 2.0f + corner / 2.0f, center.y + height / 2.0f - corner / 2.0f) controlPoint: CGPointMake(center.x - width / 2.0f + corner, center.y + height / 2.0f)];

    // path to mid left
    [path addQuadCurveToPoint: CGPointMake(center.x - width / 2.0f, center.y) controlPoint: CGPointMake(center.x - width / 2.0f, center.y + height / 2.0 - corner)];

    // path to top left

    [path addQuadCurveToPoint: CGPointMake(center.x - width / 2.0f + corner / 2.0f, center.y - height / 2.0f + corner / 2.0f) controlPoint: CGPointMake(center.x - width / 2.0f, center.y - height / 2.0f + corner)];

    [path closePath];

    return path;
}

Without adding mask for UIViews it works very fast

回答1:

There are two quick techniques to improve performance in these situations:

  1. Before you start dragging the UIView, you can set the shouldRasterize of the layer of the view to true, and when you are done dropping it, restore shouldRasterize to false. Sometimes (especially if the dragged image could be changing) this has an adverse impact, but it's simple to try and you can see if it improves the performance.

  2. The other approach is to manually create a snapshot (e.g. render the view with its clipping to a UIImage) and replace the view with an UIImageView, and then drag that, and then when you drop it, replace it with the original view (if you need it; sometimes the snapshot is all you ever need).

I might suggest watching WWDC 2012 video iOS App Performance: Graphics and Animations which illustrates some techniques for diagnosing and resolving graphic performance issues. The video may be a few years old, but the techniques are still largely applicable. The Optimizing 2D Graphics and Animation Performance video might also offer some insights (though I think the other video is likely to be more applicable here).

By the way, there are a plethora of other tricks to improve the performance (e.g. when dragging view, use predictive touches; if the view being dragged includes a lot of transparency, maybe make an opaque snapshot to drag; etc.), but perhaps try the above first, and see if that minimizes the performance issue. Also, make sure you test this on a target device and don't rely upon testing in the simulator, as often the performance characteristics are quite different.



回答2:

Animation of masked views is inherently slow, because the render tree must be recalculated at every frame. As you rightly say, it doesn't take many such views all animating at the same time for this to become obvious (typically in stuttering). Apple's WWDC has devoted many excellent videos to this, typically in the context of scrolling (e.g. a table view); I suggest watching some those videos, which also suggest workarounds.

Basically, the best workaround is probably Don't Do That. Try other approaches, such as drawing your view so that view draws itself in the correct shape (with the outside just being transparent). That is much less strain on the drawing system because there is no mask to composite. For example, to make a view a circle, use an image view whose image is a picture of a circle. And of course an opaque view is even better, if possible.