I wanted to apply a UIEffectView
with blur over a tableView but have circular UIImageView
objects in each cell show through. I used a mask and adapted the solution from this answer to create a method that would iteratively cut out circles above each cell:
func cutCircle(inView view: UIView, rect1: CGRect, rect2: CGRect?) {
// Create new path and mask
let newMask = CAShapeLayer()
// Create path to clip
let newClipPath = UIBezierPath(rect: view.bounds)
let path1 = UIBezierPath(ovalIn: rect1)
newClipPath.append(path1)
if let rect2 = rect2 {
let path2 = UIBezierPath(ovalIn: rect2)
//FIXME: Need a way to get a union of both paths!
//newClipPath.append(path2)
}
// If view already has a mask
if let originalMask = view.layer.mask, let originalShape = originalMask as? CAShapeLayer, let originalPath = originalShape.path {
// Create bezierpath from original mask's path
let originalBezierPath = UIBezierPath(cgPath: originalPath)
// Append view's bounds to "reset" the mask path before we re-apply the original
newClipPath.append(UIBezierPath(rect: view.bounds))
// Combine new and original paths
newClipPath.append(originalBezierPath)
}
// Apply new mask
newMask.path = newClipPath.cgPath
newMask.fillRule = .evenOdd
view.layer.mask = newMask
}
This function is called on the UIEffectView
for each visible tableview cell using: for cell in tableView.visibleCells()
. It appends a new circle to the mask.
However, some items have a smaller circle icon overlay, like this:
I added the second CGRect
parameter to the method above to conditionally cut out this circle. However, the mask remains intact where the two circles overlap, like this:
I looked at a few answers here, as I needed to find a way to get the union of two UIBezierPath
objects. However, this proved very difficult. I don’t think I can use a drawing context as this is a UIEffectView
and the mask needs to be cut iteratively.
I tried changing the fill rules (.evenOdd
, .nonZero
) but this does not have the desired effect.
Are there any tips for combining two overlapping UIBezierPath
into a single mask?
The overall aim is to achieve this effect with consecutive tableview cells, but some icons will have the extra circle.
Notice how the bottom icon has the extra circle but it is cropped, and my current technique to cut out this extra circle causes the problem noted above, where the overlap is not masked as expected.
You could use addArcWithCenter method to combine two arcs into desired shape.eg:
#define DEGREES_TO_RADIANS(degrees)((M_PI * degrees)/180)
- (UIBezierPath*)createPath
{
UIBezierPath* path = [[UIBezierPath alloc]init];
[path addArcWithCenter:CGPointMake(25, 25) radius:25 startAngle:DEGREES_TO_RADIANS(30) endAngle:DEGREES_TO_RADIANS(60) clockwise:false];
[path addArcWithCenter:CGPointMake(40, 40) radius:10 startAngle:DEGREES_TO_RADIANS(330) endAngle:DEGREES_TO_RADIANS(120) clockwise:true];
[path closePath];
return path;
}
I wasn't able to find out the exact points but if you could adjust the constants you could create the perfect shape required.