31

I've seen similar questions, but haven't found workable answers.

I want to mask a UIView using a grey image (need to convert to alpha scale for masking). The UIView has background. It should be easy to mask an image, but I want to mask any UIView.

Any clues will be appreciated.

subchap
  • 847
  • 2
  • 10
  • 15

3 Answers3

68

I've been working on this problem for a couple of hours and have a solution that I think will do what you want. First, create your masking image using whatever means you see fit. Note that we only need the alpha values here, all other colours will be ignored, so make certain that the method you use supports alpha values. In this example I'm loading from a .png file, but don't try it with .jpg files as they don't have alpha values.

Next, create a new layer, assign your mask to its contents and set this new layer to your UIView's own layer, like so: you should find that this masks the UIView and all its attached subviews:

UIImage *_maskingImage = [UIImage imageNamed:@"mask"];
CALayer *_maskingLayer = [CALayer layer];
_maskingLayer.frame = theView.bounds;
[_maskingLayer setContents:(id)[_maskingImage CGImage]];
[theView.layer setMask:_maskingLayer];

With this done, you can set the UIView's background colour to whatever you like and the mask will be used to create a coloured filter.

EDIT: As of iOS8 you can now mask a view simply by assigning another view to its maskView property. The general rules stay the same in that the maskView's alpha layer is used to determine the opacity of the view it is applied to.

Ash
  • 9,064
  • 3
  • 48
  • 59
  • Thanks for your answer. The problem is that I only have images with grey scale (alpha==1 for all points). I want to convert the grey scale image to an alpha image. Do you have any idea? – subchap Aug 30 '11 at 04:08
  • 2
    Well the best way to do it is to take it into an image editing suite like Photoshop and do the conversion there. The alternative would be to do it programmatically by making a new image context, then going through pixel-by-pixel on the old image reading the grey component, and converting that into the alpha component for your new colour before plotting it into your new image. This is laborious and a waste of time though, as you'd use less processor time by doing it in a paint package. – Ash Aug 30 '11 at 06:37
  • 1
    In photoshop this is easily done: (1) create a new layer (2) fill a portion of it with black (3) give it a layer mask (4) past your greyscale image into the mask. Black = transparent, White = Opaque, greys are varying degrees of transparency. (5) Apply the layer mask (right click on the mask itself in the layers panel and click 'apply layer mask') (6) crop out the portion of the layer you need. – Christopher Swasey Oct 16 '12 at 17:00
  • I want to say I downvoted on accident and now it won't let me undownvote :( This is a great answer! – Tim Jun 14 '13 at 18:35
9

For apps targeting iOS 8.0+ this worked well (in this case, using a gradient as the mask) It avoids any need to resize or position the mask.

// Add gradient mask to view
func addGradientMask(targetView: UIView)
{
    let gradientMask = CAGradientLayer()

    gradientMask.frame = targetView.bounds
    gradientMask.colors = [UIColor.blackColor().CGColor, UIColor.clearColor().CGColor]
    gradientMask.locations = [0.8, 1.0]

    let maskView: UIView = UIView()
    maskView.layer.addSublayer(gradientMask)

    targetView.maskView = maskView 
}

In my case, I want to remove the mask once the user starts scrolling. This is done with:

func scrollViewWillBeginDragging(scrollView: UIScrollView) {

    exerDetailsTableView.maskView = nil        
}

where the view is defined as an @IBOutlet:

@IBOutlet weak var exerDetailsTableView: UITableView!

Result:

example screenshot

Roi Mulia
  • 5,626
  • 11
  • 54
  • 105
Stonetip
  • 1,150
  • 10
  • 20
1

I don't know the exact code off the top of my head but the basic idea is to have two UIViews. One UIView would have it's image property set to be the grey scale image and the other UIView would be set as usual the only difference is that you would position the initial UIView directly on top of the UIView containing the "normal" image.

I hope that is enough to push your idea a step further.

  • Thanks for your answer. I didn't make it clear, but what I want is to convert the grey scale image into alpha image (just like the normal masking does), and apply it to the UIView. – subchap Dec 30 '10 at 04:59