Tag Archives: UIView

How to write a Custom Initialiser in Swift

I’m used to initialising my Objective-C objects with a custom initialiser. It’s a trick I’ve learnt from the legendary Simon Allardice back in the day. It works a treat every time!

Turns out it’s a Cocoa and Cocoa Touch design pattern, and the principle can be applied similarly in Swift, with a couple of important differences.

Or shall I say pitfalls?

Continue reading





How to handle device rotation since iOS 8

Back in the iOS 5 days, there was a method called shouldAutorotateToInterfaceOrientation. Since iOS 8 we’re no longer meant to use that, and instead use a much better technique: size classes.

In a nutshell, iOS 8 and above will call the viewWillTransitionToSize method on your UIViews. This looks a bit more complex than it actually is, because it contains two optional blocks:

Continue reading





How to apply Blur Effects to images and views in iOS 8

This slideshow requires JavaScript.

In iOS 8 there’s a new class called UIVisualEffect with which you can apply blur effects to entire views. Reading the Class Reference however you’d never figure out how.

In a nutshell, we need to create a UIVisualEffect (either a UIBlurEffect or a UIVibrancyEffect) which is applied to a UIVisualEffectView. The latter needs the same size as the view we want to blur and is then added as a subview to the view we’d like to apply an effect to.

This sounds way more complicated than it really is. Imagine this: you have a UIView, any view will do. To it you add a subview (the UIVisualEffectView). The effect view is created with an effect.

So as soon as you apply the effect view, all other existing views below it are blurred. Anything above the effect view is not blurred. Remove the effect view and the blur goes away again.

Here’s an example:

// show image
self.imageView.image = [UIImage imageNamed:@"boat6"];

// create effect
UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

// add effect to an effect view
UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blur];
effectView.frame = self.view.frame;

// add the effect view to the image view
[self.imageView addSubview:effectView];

In this example we have a UIImageView which is referenced in the storyboard. To it we apply the desired effect.

The UIBlurEffect can be created with three options and no other parameters:

  • UIBlurEffectStyleLight
  • UIBlurEffectStyleExtraLight
  • UIBlurEffectStyleDark

 

UIVibrancyEffect

There’s an additional (disappointing) UIVibrancyEffect which cannot be used on its own, only in conjunction with a blur effect. To use the vibrancy effect, we need to first create a blur, then a new vibrancy effect with that blur. From both effects we need to then create two separate effect views and add both of those to the view we’d like to blur.

Here’s an example:

// show image
self.imageView.image = [UIImage imageNamed:@"boat6"];

// create blur effect
UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

// create vibrancy effect
UIVibrancyEffect *vibrancy = [UIVibrancyEffect effectForBlurEffect:blur];

// add blur to an effect view
UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blur];
effectView.frame = self.view.frame;

// add vibrancy to yet another effect view
UIVisualEffectView *vibrantView = [[UIVisualEffectView alloc]initWithEffect:vibrancy];
vibrantView.frame = self.view.frame;

// add both effect views to the image view
[self.imageView addSubview:effectView];
[self.imageView addSubview:vibrantView];

I know… this seems an awful lot of trouble to get an effect which isn’t even all that good. But then, “new things” aren’t always “improvements” these days (the 2014 Mac Mini springs to mind).

 

How to do this in iOS 7

If you’re as disappointed by the results as I am, take a look at a UIImage Category with which Apple have demonstrated this effect at WWDC 2013. Look for a sample project called UIImageEffects.

The category is free to use and redistribute and allows for greater control over such things as colour tint and blur radius:

 

Further Reading





How to take a screeshot in iOS programmatically

In iOS we can press the HOME and the POWER button together at any time and a screenshot of what’s currently being displayed will be saved to the Camera Roll as if by magic. If we wanted to do the same thing programmatically it’s not that easy. It appears there’s no iOS system method that does this for us.

We have several options, let me describe two of those. I’ll add others if there are more convenient methods.

OPTION 1: using UIWindow

To make sure we screengrab everything in our display we can transfer the content of our top most UIWindow into a graphics context with the size of our screen. This will work no matter which class you use it in:

// create graphics context with screen size
CGRect screenRect = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContext(screenRect.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blackColor] set];
CGContextFillRect(ctx, screenRect);

// grab reference to our window
UIWindow *window = [UIApplication sharedApplication].keyWindow;

// transfer content into our context
[window.layer renderInContext:ctx];
UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

The advantage with this method is that even popovers and alert views are added to the resulting UIImage.

OPTION 2: using UIView

If we only need to turn a UIView into a UIImage then the next method will work fine. The disadvantage is that certain types of views (such as OpenGL and popovers) will not be captured. In addition, you need a reference to the UIView you’d like to capture. In this example I’m using my Master/Detail App’s split view controller:

// grab reference to the view you'd like to capture
UIView *wholeScreen = self.splitViewController.view;

// define the size and grab a UIImage from it
UIGraphicsBeginImageContextWithOptions(wholeScreen.bounds.size, wholeScreen.opaque, 0.0);
[wholeScreen.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Saving a UIImage to Camera Roll

The result of both methods above is a UIImage you can do with as you please. Let’s save it to the Camera Roll for now:

// save screengrab to Camera Roll
UIImageWriteToSavedPhotosAlbum(screengrab, nil, nil, nil);

One thing of note:
If you call either method above via a standard button, the screenshot is taken during the button animation (half faded for example).

Further Reading





How to animate a UIView

In this example we have two UIViews:

  • one backgroundView which does not change, and
  • one numberView which can be moved, for example by a pan gesture (we’re not dealing with that though)

Once the user lets go of the movable numberView, we want to reset the view back to the middle, to the same position as the backgroundView. Here’s how we do that:

    // setup animation parameters
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationDelay:0.1];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
    
    // define what we're changing
    [self.numberView setCenter:self.backgroundView.center];
    
    // start animating
    [UIView commitAnimations];

Find more details in Apple’s UI View Class Reference





How to change the background colour of a UIView

You can use the backgroundColor property for this:

self.yourView.backgroundColor = [UIColor purpleColor];

Pre-defined values are

  • blackColor
  • darkGrayColor
  • lightGrayColor
  • whiteColor
  • grayColor
  • redColor
  • greenColor
  • blueColor
  • cyanColor
  • yellowColor
  • magentaColor
  • orangeColor
  • purpleColor
  • brownColor
  • clearColor

You can also define your own colours by creating a UIColor object (from RGB or HSL values). Here’s how you can create your own RGB colour and use it with the above example:

UIColor *myPurple = [[UIColor alloc]initWithRed:1 green:0.5 blue:1 alpha:1];
self.yourView.backgroundColor = myPurple;

RGB and alpha must be defined as CGFloat numbers, i.e. between 0 and 1. The alpha value is the opacity, so 1 is fully visible and 0 is invisible.