0

After searching numerous sources on how to mask an image in Swift, I've found many that utilize UIImage rather than UIImageView. It's getting quite confusing because they are almost similar yet they don't share some of the same subclasses & properties.

I have an image that will be added into a stacks view although I'd like this image to be masked with a circular shape with a fixed start and end angle.

Example:

Original Picture and Desired Mask Result

Original Picture and Desired Mask Result

I'd like to emphasize that I am simulating a pie being sliced out so essentially I am cropping an image with the Pie's size.

Here's what I've attempted so far to get started (and I keep failing)...

let testPicture:UIImageView = UIImageView(image: UIImage(named: "myPicture"))
testPicture.contentMode = .ScaleAspectFit
testPicture.layer.borderWidth = 1
testPicture.clipsToBounds = true
testPicture.layer.masksToBounds = true
view.layer.addSublayer(shapeLayer)

// ???
// UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: clockwise).CGPath

self.myStackView.addArrangedSubview(testPicture)
self.myStackView.layoutIfNeeded()

I just can't figure out how to apply the same implementation of masking images with geometric functions when other sources out there solely use UIImage.

New Code (Attempt) to Generate Pie Mask

let center = CGPointMake(testPicture.frame.size.width / 2, testPicture.frame.size.height / 2)
let radius = CGFloat((CGFloat(testPicture.frame.size.width) - CGFloat(1.0)) / 2)
let midX = (testPicture.layer.frame.width-testPicture.layer.frame.width)/2
let midY = (testPicture.layer.frame.height-testPicture.layer.frame.height)/2

let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX , y: midY), radius: radius, startAngle: CGFloat(10), endAngle:CGFloat(M_PI * 2), clockwise: true)

let maskLayer = CAShapeLayer()
maskLayer.path = circlePath.CGPath

testPicture.layer.mask = maskLayer
testPicture.clipsToBounds = true
testPicture.layer.masksToBounds = true
theflarenet
  • 642
  • 2
  • 13
  • 27
  • `UIImage` and `UIImageView` are completely different and share nothing. A `UIImage` corresponds to the model of an image, it contains, among other things, the raw bits of the image, and mechanisms for reading/writing images from various formats. `UIImageView` corresponds to the view of the image, it's responsible only for the DISPLAY of a `UIImage` – David Berry Mar 18 '16 at 16:19
  • You'll want to add your `UIBezierPath` to a `CAShapeLayer` and use that to mask your `UIImageView`'s layer. Although I'm not sure what you're trying to do by setting `masksToBounds` to false, then `clipsToBounds` to true... The view's `clipsToBounds` is just a forwarding property for the underlying layer's `masksToBounds`. They do the same thing. – Hamish Mar 18 '16 at 16:26
  • You're right! Whoops, a silly mistake. I'm starting to believe UIBezierPath won't give me my desired Pie masking. Currently looking for the correct drawing! :-| – theflarenet Mar 18 '16 at 19:08
  • In your new code you never set the frame of the `maskLayer` - you need to set that to the bounds of the `testPicture` – Hamish Mar 18 '16 at 19:15
  • Since you're mutating the question, I'm not sure what you're actually asking at this point. – David Berry Mar 18 '16 at 19:36
  • I'm not necessarily mutating the question. I am still trying to mask the initial image of testPicture with a Pie shape just as my image depicts. Not sure whether UIBezierPath or your suggestion is bringing me closer to the solution. Still attempting to figure this out. – theflarenet Mar 18 '16 at 19:47
  • Perhaps the best solution is just to close this as a duplicate of http://stackoverflow.com/questions/5757386/how-to-mask-an-uiimageview then. – David Berry Mar 18 '16 at 19:56
  • I beg to differ. This is not written in Swift and I have already experimented with the other answers to simulate the Pie cropping on the image. It was a no-go. – theflarenet Mar 18 '16 at 20:20

1 Answers1

2

To mask a layer you assign a separate layer to the mask property. In this case, I think what you're looking for is:

testPicture.layer.mask = shapeLayer
David Berry
  • 40,941
  • 12
  • 84
  • 95
  • Good answer! This has helped me get a step further as I tried to accomplish the desired result; however, I just realized the geometric function I had to draw a PIE wasn't the right one. Apparently I have to use UIGraphicsGetCurrentContext()... I think. If that is the case, the masking won't work. :-( I've updated my code – theflarenet Mar 18 '16 at 19:04
  • The easiest approach may be to create your pie as a CGPath and then create a CAShapeLayer from that, but that's a different question :) – David Berry Mar 18 '16 at 19:11
  • Which I now see that you're doing... Given that you're using `UIBezierPath` you shouldn't need to worry about the graphics context. – David Berry Mar 18 '16 at 19:35
  • I am actually using a PNG image so I suppose using UIBezierPath to draw a Pie in terms of masking it, as my image shows, would be the solution. The PNG image would be the gradient square (or perhaps a picture of Apple Pie), and I would want to simulate a cropped result of slices taken out from that image. – theflarenet Mar 18 '16 at 19:53
  • Ok. I've figured it out and your suggestion worked; however, it does not mask within the same size of the subview's testPicture boundaries and .ScaleAspectFit contentMode property. I suppose this will be a follow up question elsewhere so I'll thank you for helping me get ahead! – theflarenet Mar 22 '16 at 17:46
  • Follow up question in case anyone is interested and would like to see where this follows: http://stackoverflow.com/questions/36162215/stack-view-scaleaspectfit-mask-resize-in-swift – theflarenet Mar 22 '16 at 18:47