CALayer and Quartz Transparency - iphone

I have a CALayer subclass. I have overridden the drawInContext method. I want the majority of my layer to be transparent except a few areas. I'm using the layer as a menu and I want the icons and labels on the menu to be opaque.
Is it possible to have a CALayer's sublayers be opaque if the super CALayer is transparent?
Is it possible to draw opaque tems in the drawInContext method of a transparent CALayer? I have tried using CGContextSetAlpha, but I assume it doesn't work since the CALayer that I am drawing for is transparent.
As always, any help would be great.

I found out that it is possible. A super layer does not dictate the transparency of its sublayer.

Related

Feathering NSView Opacity

I wish to have an NSView with one side of it fading out to an alpha of 0.0f. What is the best practice for doing this? This effect is similar to that of feathering a selection in Photoshop or Pixelmator.
Give your view a backing store layer (check out the NSView wantsLayer and layer properties). Make a CAGradientLayer and set its your backing store layer's mask.
The most basic way to do this is to draw a gradient and, in your view's drawRect:, call CGContextClipToMask() to use the gradient image as a mask.
Make a .png image that starts from transparent and fades out to the color that you want to your NSView to fade out to.
Then add an image element that covers all the NSView and display the .png image that you made before.
That should do it.

Border image on UIView

I want to have a UIView subclass that has a border image, but I don't want or care about this 'new' frame/bounds around the border image itself.
What I wanted to do was just use drawRect and draw outside of the rect but all drawing is clipped and I don't see a way to not clip drawing outside of this context rect.
So now I have added a sublayer to the views layer, set [self clipsToBounds] on the view and override setFrame to control my sublayers frame and always keep it at the proper size (spilling over the views frame by 40px).
The problem with this is that setFrame on a uiview by default has no animation but seTFrame on a calayer does.
I cant just disable the animations on the calayers setFrame because if I were to call setFrame on the uiview inside a uiview animation block the calayer would still have its animation disabled.
The obvious solution is to look up the current animationDuration on the uiview animation and set a matching animation on the sublayer, but I don't know if this value is available. And even if it is, I'm afraid that calling an animation from within another animation is wrong.
Unfortunately the best solution is to not use a calayer at all and just add a uiview as a subview and draw into that just like I am drawing into my layer, and hope that with autoresizingMask set to height and width that everything will 'just work'. Just seems like unnecessary overhead for such a simple task.
My solution would be to override the initWithFrame: to add the surrounding border pixels and contain the content in a subview. It probably is unneccesary overhead but definietly the "cocoa" route. It's probably going to be easier in the end too since a subview structure will allow you to edit the content seperatly from the border so you dont have to redraw the border when you redraw the content. And keeping them seperate simply makes sense from a OOP perspective.
The clipsToBounds route is probably the easiest route besides the subview structure but managing the border and content in one drawing cycle and in one object will probably be a lot more work so it'll be worth the overhead.
Excuse any typos, typed this from my iPhone.

How can I draw a shadow beyond a UIView's bounds?

I'm using the method described at How do I draw a shadow under a UIView? to draw shadow behind a view's content. The shadow is clipped to the view's bounds, although I disabled "Clip Subviews" in Interface Builder for the view. Is it possible to draw a shadow around a view and not only in a view?
I don't want to draw the shadow inside the view because the view would receive touch events for the shadow area, which really belongs to the background.
Instead of manual drawing in drawRect, consider setting properties on the the UIView's Core Animation layer for drawing a shadow.
For example:
[descriptionInput setClipsToBounds:NO];
[descriptionInput.layer setShadowColor:[[UIColor blackColor] CGColor]];
[descriptionInput.layer setShadowOpacity:0.8];
[descriptionInput.layer setShadowOffset:CGSizeMake(0.0, 3.0)];
For this to work, you need to include QuartzCore:
#import <QuartzCore/QuartzCore.h>
clipsToBounds only controls the clipping for children of a view, not drawing of that view itself; hence it's not solving your problem.
If you can draw your shadow onto a different view and add that as a child, it won't get clipped. However, I don't know how possible that is with the method you're using :(
It is not encouraged to draw outside view bounds. Maybe you can include the shadow directly in your background...
Regards,

composite colors: CALayer and blend mode on iPhone

I'm trying to use core image on the iphone. I'm able to composite my colors using quartz to draw an uiview, but I want to separate each component into CALayer (UIview consume more resources).
So I have a white mask I want to use to filter a background bitmap, and I want to try different blending mode. Unfortunately, the layers are only "adding" their colors.
Here is my code:
#implementation WhiteLayerHelper
- (void)drawLayer:(CALayer *)theLayer
inContext:(CGContextRef)myContext
{
// draw a white overlay, with special blending and alpha values, so that the saturation can be animated
CGContextSetBlendMode(myContext,kCGBlendModeSaturation);
CGContextSetRGBFillColor(myContext,1.0,1.0,1.0,0.9);
CGContextFillRect(myContext,[UIScreen mainScreen].bounds);
}
#end
And here is the main view drawrect code, where I use my CALayer:
- (void)drawRect:(CGRect)rect {
//get the drawing context
CGContextRef myContext = UIGraphicsGetCurrentContext();
// draw the background
[self fillContext:myContext withBounds:m_overlayRect withImage:m_currentImage];
[whiteLayer renderInContext:myContext];
}
Is there something wrong?
I managed to get the affect of compositing multiple CALayers by drawing them directly into a UIView's graphics context.
-(void)drawRect:(CGRect)rect {
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(c, kCGBlendModeDifference);
[myLayer drawInContext:c];
}
BTW, I did not add the layers as sublayers of the view's layer (that is I never called [myView.layer addSublayer:myLayer])
This method seems not to be a flaw of Core Animation, because the layers are prerendered into image contexts. Core Image is used for real time filtering (during animation and whatnot) of these images against background layers and their images. So the compositing properties of CALayer are used for this ability, which are not available on iPhone/iOS (yet) due to the requirement of Core Image.
OpenGL can do this for us in our situation, however =)
edit(add): setting the blend mode with CGContext in -drawInContext: and -drawLayer:inContext: does of course still have effect with what was already rendered or present in the image of that context. (when it is set before anything was rendered in the context('s image), it is the effect of blending against either full Black or full White (i am not sure which=)
Not at all... I think this is easier to use opengl to achieve this, because it seems to be not yet implemented in CA.

How can I blend between my UIView and my EAGLView?

I have an opengl scene rendering on an EAGLView layer and some other elements (circles and such) rendering on a UIView (which is a sibling of the EAGLView, positioned above it). Is it possible to blend colors between the two layers? I'd like to do some difference blending to get an inversion effect on the colors from EAGLView.
I've been playing around with CGBlendMode but it only seems to affect what I'm drawing in that current view. I think this has something to do with the CGContext but I'm a little hazy on the details, can I force the UIView and the EAGLView to have the same CGContext so that the blending works between them?
Help, corrections, clarifications are all appreciated. Thanks in advance,
-S
Short answer is you can not. Long answer follows.
By EAGLView you must mean the subclass of UIView that is included in the OpenGL ES Template in Xcode. What makes this class special is that the layerClass class method is overridden and return the CAEAGLLayer class instead of the CALayer class, as is default.
UIView and CALayer work in pairs. All UIView objects are backed by a CALayer, the CALayer is the object responsible for layout and rendering to screen. The UIView is a delegate to the CALayer, and is responsible for drawing it's graphics when needed.
CALayer will let it's delegate (the UIView) draw into a CGContextRef. It is one context per UIView, so you can not use CGBlendMode to blend several views since it will only function within one single UIView context.
Blending of CALayer should be done using the filter properties. These are defined for iPhone OS but the available filters are undefined according to the documentation. This is because Core Image is not available on iPhone OS at this time.
I don't think you'll be able to blend colours in that sense. The best you can do is have one completely obscuring the other, or have the top layer semi-transparent (in which case, you'll see the part underneath) - but you won't be able to do XOR type drawing.