0

I’m overlaying two UIViews with a white backgroundColor at 25% opacity. In a small part, they overlap each other, meaning that at that area, they are summed to 50% opacity.

I’d like to keep that 25% opacity, even if the two views overlap, effectively meaning that in those overlapped points, each view’s opacity drops to 12.5% to total 25%.

I’ve done a little looking into compositing but I’m not sure which of these modes would help, or how I’d go about applying them to a specific part of these two UIView instances.

(http://docs.oracle.com/javase/tutorial/2d/advanced/compositing.html is what I was reading, and I found the CGBlendMode for drawing, if it comes to using that (though I’d prefer not to if possible!))

Luke
  • 9,512
  • 15
  • 82
  • 146

2 Answers2

1

If you add them both to the same parent UIView, tell that UIView to rasterize, then set the alpha on the parent, you'll get the desired effect. I'm not sure if that fits with your display structure or performance needs.

UIView *parent = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[parent setBackgroundColor:[UIColor clearColor]];
[parent.layer setShouldRasterize:YES];
[parent.layer setRasterizationScale:[[UIScreen mainScreen] scale]];
[parent setAlpha:0.25];
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 125, 125)];
[subview1 setBackgroundColor:[UIColor whiteColor]];
[parent addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectMake(75, 75, 125, 125)];
[subview2 setBackgroundColor:[UIColor whiteColor]];
[parent addSubview:subview2];
Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • You're assuming he wants the entire contents of the view at alpha 0.25, but that's not the same as just having the `backgroundColor` at alpha 0.25. – rob mayoff Oct 14 '14 at 15:46
  • Actually, I had meant that he could add just the backgrounds, then move the contents (in a different hierarchy) in sync with the backgrounds. – Ian MacDonald Oct 14 '14 at 15:50
1

You can't control the compositing mode of views (or, really, CALayers) on iOS.

The best solution I can think of here is to leave both views with a clearColor (or nil) background, and use a single CAShapeLayer to draw the background of both. If your two views have the same parent, it's not too hard.

Let's say the parent is of type ParentView. Override layoutSubviews in ParentView to create and update the backdrop layer as necessary. Be sure to send setNeedsLayout to the parent view if you move either of the child views.

ParentView.h

#import <UIKit/UIKit.h>

@interface ParentView : UIView

@property (nonatomic, strong) IBOutlet UIView *childView0;
@property (nonatomic, strong) IBOutlet UIView *childView1;

@end

ParentView.m

#import "ParentView.h"

@implementation ParentView {
    CAShapeLayer *backdrop;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [self layoutBackdrop];
}

- (void)layoutBackdrop {
    [self createBackdropIfNeeded];
    [self arrangeBackdropBehindChildren];
    [self setBackdropPath];
}

- (void)createBackdropIfNeeded {
    if (backdrop == nil) {
        backdrop = [CAShapeLayer layer];
        backdrop.fillColor = [UIColor colorWithWhite:1 alpha:0.25].CGColor;
        backdrop.fillRule = kCAFillRuleNonZero;
        backdrop.strokeColor = nil;
    }
}

- (void)arrangeBackdropBehindChildren {
    [self.layer insertSublayer:backdrop atIndex:0];
}

- (void)setBackdropPath {
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.childView0.frame];
    [path appendPath:[UIBezierPath bezierPathWithRect:self.childView1.frame]];
    backdrop.path = path.CGPath;
}

@end
rob mayoff
  • 375,296
  • 67
  • 796
  • 848