Skip to content

Masked UIBlurEffect doesn't work on iOS 10 due to acknowledged Apple bug #16

@shirakaba

Description

@shirakaba

The UIBlurEffect is not applied, meaning that the shaded area for the tutorial is just a grey-tinted area. Without this blur, it is hard to read the tutorial texts when they are overlaying other texts.

Acknowledged on:

Here are several of the recommendations made by Apple staff member Rincewind in that thread:

Your issue is also using CALayer.mask, using UIView.maskView would probably work better for your needs (modulo bugs that exist in Beta3 at the moment).

However, fundamentally the best way to create a mask view that uses a shape layer is to create your own UIView subclass that overrides .layerClass() to return CAShapeLayer.self. That removes the extra 2 views/layers in your example and simplifies greatly by not using a mask of a subview of a view mean to be a mask.

Instead you can create a simple UIView subclass that uses a CAShapeLayer as its backing layer by overriding +layerClass.

The only solution that can work is to use UIView.maskView on the UIVisualEffectView. But without knowing what you tried its hard to understand where you might have gone wrong.

On iOS 10 blurs can't sample content "through" a mask – because you make the visual effect view a subview of a view with a mask you prevent it from sampling the content it needs to do the masking.

You need to apply the mask directly to the UIVisualEffectView, not to a superview. This works on iOS 11 due to improvements specifially made on that OS version.

So I think he recommends making a class like this:

@interface ShapeView: UIView
@end
@implementation ShapeView

+ (Class)layerClass
{
    return [CAShapeLayer class];
}
@end

... However, I'm not sure how to migrate from CALayer.mask to UIView.maskView (with the aforementioned ShapeView). I started trying to replace the relevant code after [tutorialView setNeedsDisplay], but I really don't know what I'm doing (not experienced in UI code):

ShapeView* shapeView = [[ShapeView alloc] initWithFrame:CGRectMake(0, 0, tutorialView.frame.size.width, tutorialView.frame.size.height)];
UIVisualEffect* blurEffect = [UIBlurEffect effectWithStyle: UIBlurEffectStyleRegular];
UIVisualEffectView* effectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
shapeView.frame = effectView.frame;
[tutorialView addSubview:effectView];

/* The original code: */
// CALayer* maskLayer = [CALayer layer];
// maskLayer.frame = CGRectMake(0, 0, tutorialView.frame.size.width, tutorialView.frame.size.height);
// maskLayer.contents = (__bridge id)[image CGImage];
// 
// tutorialView.layer.mask = maskLayer;

My code snippet compiles, but doesn't do anything useful (no blur, no masking of highlighted areas). Hopefully it can be of help as a starting point, though. The other starting point is the commit made in the Instructions repository, but it's rather big and hard to read through.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions