开发者

How to use a CGBlendMode on a UIView that scrolls above a fixed background?

Our main UIView is a UIScrollView with a fixed background image (very common, obviously). In that scrollView, we have several UIViews that hold content and scroll up and down as the user scrolls (also common). Those UIViews each have their own background, a simple gradient from white to black.

The goal is to have the background gradient of those (inner) UIViews be partially opaque AND use a CGBlendMode other than "kCGBlendModeNormal" (specifically, "kCGBlendModeOverlay"). You should be able to see through to the "parent" scrollView’s fixed background image as the UIViews scroll up and down above it.

- (void)drawRect:(CGRect)rect {
    gradientStart = [UIColor colorWithRed:1 green:1 blue:1 alpha:1.0];
    gradientEnd = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[2] = { 0.0f, 1.0f };
    NSArray *colors = [NSArray arrayWithObjects:(id)gradientStart.CGColor, (id)gradientEnd.CGColor, nil];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)colors, locations);
    CGColorSpaceRelease(colorSpace);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetAlpha(context, 0.50); //this works!
    CGContextSetBlendMode(context, kCGBlendModeOverlay); //doesn’t seem to do anything!

    CGContextClearRect(context, rect);

    CGPoint startPoint, endPoint;
    startPoint.x = 0.0;
    startPoint.y = 0.0;
    endPoint.x = 0.0;
    endPoint.y = rect.size.height;

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);

    CGGradientRelease(gradient);

    [super drawRect:rect];
}

Everything works as expected except the CGContextSetBlendMode, which is ignored. We can't seem to find a way to change the blendMode of a UIView relative to what is behind it, the s开发者_开发技巧ame way you can with alpha. Please note that this is different than building up multiple layers in a SINGLE UIView; in that case, this technique does change the blendMode of the layers "on top". We want to see through to the parent scrollView's fixed background image (as we scroll the child view up and down above it), with both an alpha and an overlay blend applied.

Here's an image showing the issue: http://img2.sbck.us/blendmode.png

Thanks in advance for your help!


I believe what you want is not possible with your current setup. On iOS, it is simply not possible for the blend mode of a view to have an effect on the stuff that is drawn under the view. You would have to draw the scroll view's background and the gradients in the same view.


This is possible, at least with two image views. It might even be possible with more general views. The approach is to implement drawRect in the parent view, and do as follows:

  1. Determine the rect for the foreground view.
  2. Convert the rect in the foreground view to a rect in the background view.
  3. Begin a new graphics context.
  4. Draw the background with the proper blend mode.
  5. Draw the foreground with the proper blend mode.
  6. Extract the image from the graphics context.
  7. End the graphics context.
  8. Use the extracted image accordingly.

This allows a foreground image to blend with a background image.


Seems like you could do this by setting the 'compositingFilter' property of your view's CALayer. The comment in CALayer.h says "A filter object used to composite the layer with its (possibly filtered) background. Default value is nil, which implies source-over compositing."

Alas, CoreImage which provides the filters is not (officially) available on iOS.

I guess your other alternative would be to use OpenGL. You could still use UIView with OpenGL after a fashion by rendering your UIView's into images which could then be used a textures.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜