How to replicate the blurred text in Notification

2019-01-13 06:06发布

问题:

I am playing with TodayExtension in iOS 8 and I wondered how to apply that blur effect to the Text or to buttons. I already figured out that it has something to do with UIVisualEffectView. But I don't know how to use it.

I am using Objective-C

Can anyone explain it to me how to achieve this?

Thanks, David

回答1:

Updated Answer for iOS 10

In iOS 10, you can use widgetPrimaryVibrancyEffect and widgetSecondaryVibrancyEffect to automatically return a UIVibrancyEffect object.

Check out the documentation here and here.

Answer for iOS 9

Use this code to apply a vibrancy effect to your whole widget:

UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:[UIVibrancyEffect notificationCenterVibrancyEffect]];
effectView.frame = self.view.bounds
effectView.autoresizingMask = self.view.autoresizingMask;

__strong UIView *oldView = self.view;

self.view = effectView;

[effectView.contentView addSubview:oldView];

self.view.tintColor = [UIColor clearColor];


回答2:

You are actually looking at two effects here. The background has a blur effect applied and the labels have a vibrancy effect applied.

For the blur effect you first initialize a UIBlurEffect with a style (dark, light, extra light):

UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];

For the vibrancy effect you initialize a UIVibrancyEffect with the blur effect you just created:

UIVibrancyEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:blurEffect];

This is because the vibrancy effect needs to take the underlying blur effect into account.

Next you create two UIVisualEffectViews:

UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
UIVisualEffectView *vibrancyEffectView = [[UIVisualEffectView alloc] initWithEffect:vibrancyEffect];

These need to be added to the view hierarchy. UIVisualEffectView has a contentView property to which you must add subviews to which you want the respective effect applied. Ensure that vibrancyEffectView is added over, or as a subview of the contentView of, the blurEffectView.

You can also set all this up in IB (I'm using Xcode 6 beta 5). There is a "Visual Effect View with Blur" and a "Visual Effect Views with Blur and Vibrancy" in the Object Library that you can drag to a view. The "Visual Effect Views with Blur and Vibrancy" sets up two UIVisualEffectViews nested as described above.

Check out WWDC14 Session 221 and the UIVisualEffectView.h header for more info.



回答3:

The "Bearbeiten" button can be recreated by drawing a see through text on the button. How to do this has been answered in this post.

Please see below for my solution. The original iOS "Bearbeiten" still looks a bit different. I've made it look similar by changing the alpha. Not the right solution. Hope that this post will trigger someone to find the correct way to do it (and share it).

In viewDidLoad:

_pinButton.backgroundColor = [UIColor clearColor];
_pinButton.layer.cornerRadius = 4.0;
_pinButton.clipsToBounds = YES;

UIColor *white = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.75];
UIColor *whiteT = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.3];
UIFont *buttonFont = [UIFont fontWithName:@"HelveticaNeue" size:12.0];

[_pinButton setImage:[self imageWithCutOutString:@"Pin" 
                                            size:_pinButton.frame.size 
                                 backgroundColor:white 
                                            font:buttonFont] 
            forState:UIControlStateNormal];

[_pinButton setImage:[self imageWithCutOutString:@"Pin" 
                                            size:_pinButton.frame.size 
                                 backgroundColor:whiteT 
                                            font:buttonFont]
            forState:UIControlStateHighlighted];

And the actual imageWithCutOutString method itself:

- (UIImage *)imageWithCutOutString:(NSString *)string size:(CGSize)size backgroundColor:(UIColor *)backgroundColor font:(UIFont *)font
{
    NSDictionary *textAttributes = @{ NSFontAttributeName:font };

    CGSize textSize = [string sizeWithAttributes:textAttributes];

    UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(ctx, backgroundColor.CGColor);

    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0.0, 0.0, size.width, size.height)];
    CGContextAddPath(ctx, path.CGPath);
    CGContextFillPath(ctx);

    CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
    CGPoint center = CGPointMake((size.width - textSize.width) / 2.0, (size.height - textSize.height) / 2.0);
    [string drawAtPoint:center withAttributes:textAttributes];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}


回答4:

I have tried the examples above but none of them seemed working out of the box. Here is a similar example which works for me:

- (void)viewDidLoad {
    [super viewDidLoad];

    UIVibrancyEffect *effect = [UIVibrancyEffect notificationCenterVibrancyEffect];

    UIVisualEffectView *outer = [[UIVisualEffectView alloc] initWithEffect:effect];
    outer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    outer.frame = self.view.bounds;

    UIVisualEffectView *inner = [[UIVisualEffectView alloc] initWithEffect:effect];
    inner.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    inner.frame = self.view.bounds;

    UILabel *label = [UILabel new];
    label.text = @"HELLO, I am a vibrant label";
    label.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    label.frame = self.view.bounds;

    [inner.contentView addSubview:label];
    [outer.contentView addSubview:inner];
    [self.view addSubview:outer];
}


回答5:

I was able to achieve the "Bearbeiten" button using AYVibrantButton with the AYVibrantButtonStyleFill style:

// Create the button
AYVibrantButton* moreButton = [[AYVibrantButton alloc] initWithFrame:CGRectMake(0, 0, 210, 30) style:AYVibrantButtonStyleFill];
// Set the vibrancy effect to the one provided by notification center
moreButton.vibrancyEffect = [UIVibrancyEffect notificationCenterVibrancyEffect];
// Setup basic button properties
moreButton.text = @"Show More..";
moreButton.font = [UIFont systemFontOfSize:13.0];
// Add it to your view
[self.view addSubview:moreButton];