21

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

enter image description here

gcamp
  • 14,622
  • 4
  • 54
  • 85
David Gölzhäuser
  • 3,525
  • 8
  • 50
  • 98

5 Answers5

23

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];
BalestraPatrick
  • 9,944
  • 4
  • 30
  • 43
  • 3
    This does not help creating the button at the bottom, shown in the question. How can we do that? – frankish Sep 25 '14 at 08:58
  • I agree @frankish just applying a vibrancy effect with a dark blur (equivalent to notificationCenterVibrancyEffect) do not recreate the exact same style as the one of the Edit button. The edit button is less "vibrant" – Aurelien Porte Sep 25 '14 at 10:21
9

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.

  • Should you actually add another blur when the notification center already has blur? I think  is providing the [UIVibrancyEffect notificationCenterVibrancyEffect] for a reason.. – Maciej Swic Jul 30 '15 at 08:52
0

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;
}
Community
  • 1
  • 1
0

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];
}
gklka
  • 2,459
  • 1
  • 26
  • 53
0

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];
Ken Toh
  • 3,721
  • 1
  • 24
  • 30