I have this following codes:
#implementation MyImageView
#synthesize image; //image is a UIImage
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void) removeFromSuperview
{
self.image = nil;
[super removeFromSuperview];
}
- (void)drawRect:(CGRect)rect
{
// Drawing code
if (self.image)
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
//the below 2 lines is to prove that the alpha channel of my UIImage is indeed drawn
//CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
//CGContextFillRect(context, rect);
CGContextDrawImage(context, self.bounds, self.image.CGImage);
}
}
#end
When I ran the code, I realized that the background of my view is black. To test if it was a problem with my UIImage, I used the 2 lines commented after CGContextClearRect(context, rect). Indeed a white background was drawn. Is there anyway for me to remove the black background? When I init MyImageView, i have already set backgroundColor to [UIColor clearColor].
Any advice is much appreciated.
Thanks
Setting the background color to [UIColor clearColor] should work. Also set self.opaque = NO to enable transparency.
You should also check that the correct initializer is being called. For example if the view is part of a XIB file, you need to implement initWithCoder: as well as initWithFrame: etc.
I had the same issue - this worked for me (Swift example)
var backgroundImage = UIImage() //background image - size = 100x100
var frontImage = UIImage() //smaller image to be drawn in the middle
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), false, 0.0) //false here indicates transparent
var context = UIGraphicsGetCurrentContext()!
UIGraphicsPushContext(context)
backgroundImage.drawInRect(CGRectMake(0, 0, 100, 100))
frontImage.drawInRect(CGRectMake((100 - frontImage.size.width) / 2, (diameter - frontImage.size.height) / 2, frontImage.size.width, frontImage.size.height))
UIGraphicsPopContext()
var outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Your CGContext will draw upside down
anyhow, so just go the easy route and use
[self.image drawInRect:CGRectMake(rect)];
Instead.
Related
Hey I am trying to add a shadow to all UINavigationBars in my project. I have tried a number of things recommended on this site and on other internet tutorials but have had no luck in getting a shadow to stick. I have tried putting it in using a shadow image I have created in photoshop, and calling the following in the main appDelegate:
[[UINavigationBar appearance] setShadowImage:[UIImage imageNamed:#"shadowTest.png"]];
I have subclassed the UINavigationBar out and tried to assign the property from within the class inside the awakeFromNib method and still nothing. I then tried to manually create the shadow with <QuartzCore/QuartzCore.h> image framework but nothing happened. I am using the subclass to override the drawRect method, could this be causing my problem? Here is the UINavigationBar class with my latest attempt at getting the shadow to stick.
#import "BasicNavigationBar.h"
#implementation BasicNavigationBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
}
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
// draw shadow
self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(0, 3);
self.layer.shadowOpacity = 1.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, rect);
}
#end
setShadowImage doesn't work if you don't set the backgroundImage, too.
For a custom shadow image to be shown, a custom background image must also be set with the setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow image will be used regardless of the value of this property.
I'd like to add shadow to a UIImageView which has image layers.
I've tried self.layer.shadowOffset/shadowOpacity route, but it's too slow..
When I want to add a shadow, I call addShadowLayerWithOffset method below which I expected to call drawRect and add shadow..
But drawRect isn't getting called.
What am I missing here?
- (void)drawRect:(CGRect)rect
{
SYSLOG(LOG_DEBUG, "in drawRect, isShadowed: %d", isShadowed);
if (isShadowed == true)
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetShadow(currentContext, CGSizeMake(100, 100), 3);
[super drawRect: rect];
CGContextRestoreGState(currentContext);
}
else
[super drawRect: rect];
}
- (void) addShadowLayerWithOffset: (int)offset
{
// self.layer.shadowOffset = CGSizeMake(offset,offset);
// self.layer.shadowOpacity = 0.7f;
// self.layer.shadowRadius = 5.0;
isShadowed = true;
[self setNeedsDisplay];
}
EDIT
ok, I got drawLayer being called.
I needed [self.layer setNeedsDisplay] not [self.layer setNeedsPlay] where self is the UIImageView subclass.
But shadow is not being drawn, in fact image(original layer) itself is not shown either.
What should I change?
- (void) drawLayer: (CALayer*) layer inContext: (CGContextRef)context
{
SYSLOG(LOG_DEBUG, "in drawLayer, isShadowed: %d", isShadowed);
if(isShadowed == true)
{
CGContextSaveGState(context);
CGContextSetShadow(context, CGSizeMake(10, 10), 3);
[super drawLayer: layer inContext: context];
CGContextRestoreGState(context);
}
else
[super drawLayer: layer inContext: context];
}
try to call this method:
called by a UIViewController:
[self addShadowedLayer:self.view inRect:( CGRectMake(30, 30, 128, 192))];
- (void)addShadowedLayer:(UIView *)aUIView inRect:(CGRect)aRect {
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
sublayer.shadowOffset = CGSizeMake(0, 3);
sublayer.shadowRadius = 5.0;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shadowOpacity = 0.8;
sublayer.frame = aRect;
sublayer.cornerRadius = 26.0;
[aUIView.layer addSublayer:sublayer];
}
it just add a white rounded rect, but what you need is just its shadow...
you are calling:
[super drawRect: rect];
but apple says:
You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay or setNeedsDisplayInRect: method instead.
instead of drawRect, ever tried drawLayer?
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
I think you are barking up the wrong tree. You said that specifying the shadow directly on the image layer is too slow. That is correct because the OS uses the alpha channel to determine where to draw the shadow.
What you can do to improve the rendering performance on iOS 3.2 and later is that you specify a shadow path. You first create a CGPathRef and set it as the shadow path of the layer.
This should improve rendering dramatically without having you to introduce another layer just for the shadow.
I am trying to get a transparent background in CG but it keeps coming out black.
I have the following code:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
DLog(#">>> Alloc: DrawingCanvas [0x%X]", (unsigned int)self);
[self setOpaque:NO];
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void) drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect frame = rect;
int counter = 3;
CGContextClearRect(context, frame);
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, frame);
}
How do I get this code to show a transparent background?
With that setup and as long as you don't set clearsContextBeforeDrawing to NO, the background should already be transparent when your drawRect: method is called. Remove the CGContextClearRect and other drawing calls.
You could simply remove these lines :
CGContextClearRect(context, frame);
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, frame);
As long as you have set opaque to NO and clearColor as backgroundColor everything should be fine.
Be careful when drawing since your other drawing code may fill the background entirely (take care of [path fill] things in a non-clipped context).
I had this same problem and the solution was to set the backgroundColor property of the UIView which I was drawing in, from the parent view's class. I didn't need any code to clear the background in the UIView's class where the drawing happens.
myDrawingView.backgroundColor = [UIColor clearColor];
I have a main view with a picture on it.
I am trying to add a subview with [self.view addSubview:view2]; but I want the view2 background to be transparent. Have tried opaque=no and background color to clearcolor and also tried to subclass a uiview and rewrite the drawrect with:
#import "TransparentView.h"
#implementation TransparentView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor clearColor]];
self.opaque=NO;
self.clearsContextBeforeDrawing=YES;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, rect);
}
#end
But still doesn't display the background of the subview transparent... any ideas?
Try:
view.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.0];
view.opaque = NO;
Is the view being loaded from a nib file? If so, the -initWithFrame: won't be called; -initWithCoder: will be called instead. A better place to do this initialization might be in -viewDidLoad. But setting the background color to [UIColor clearColor] should definitely do the trick.
Try coloring the subview's background with a 0.0 for Alpha. That should make it completely transparent.
Something like this:
UIColor *myUIColor = [UIColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha:0.0];
In the function
- (void)drawRect:(CGRect)rect
try to update
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
to
const CGFloat BACKGROUND_OPACITY = 0.85; //Note: update this value to what you need
CGContextSetRGBFillColor(context, 1, 1, 1, BACKGROUND_OPACITY); // You can change 1,1,1 to the needed values
This link might help you
http://www.cocoawithlove.com/2009/04/showing-message-over-iphone-keyboard.html
I've had some cases where ... addSubview:clearView] seemed to reset the background color of clearView (WTF!) to something not clear. I added a
[clearView setBackgroundColor:nil];
somewhere after that and it seemed to help.
I am still struggling with drawing a line with CGContext. I have actually go to line to draw, but now I need the background of the Rect to be transparent so the existing background shows thru. Here's my test code:
(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextSetAlpha(context,0.0);
CGContextFillRect(context, rect);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, 100.0,0.0);
CGContextAddLineToPoint(context,100.0, 100.0);
CGContextStrokePath(context);
}
Any ideas?
After UIGraphicsGetCurrentContext() call CGContextClearRect(context,rect)
Edit:
Alright, got it.
Your custom view with the line should have the following:
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, 100.0,0.0);
CGContextAddLineToPoint(context,100.0, 100.0);
CGContextStrokePath(context);
}
My test used this as a very basic UIViewController:
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *v = [[UIImageView alloc] initWithFrame:self.view.bounds];
[v setBackgroundColor:[UIColor redColor]];
[self.view addSubview:v];
TopView *t = [[TopView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:t];
[v release];
[t release];
}
Easy way:
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
self.opaque = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
//your code
}
Init a context with opaque == false, Swift 3
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
opaque
A Boolean flag indicating whether the bitmap is opaque. If you know the bitmap is fully opaque, specify true to ignore the alpha channel and optimize the bitmap’s storage. Specifying false means that the bitmap must include an alpha channel to handle any partially transparent pixels.
This is what worked for me with a UIImage which had been manually added using InterfaceBuilder.
- (id)initWithCoder:(NSCoder *)aDecoder {
if(self = [super initWithCoder:aDecoder]) {
self.backgroundColor = [UIColor clearColor];
}
return self;
}
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, 100.0,0.0);
CGContextAddLineToPoint(context,100.0, 100.0);
CGContextStrokePath(context);
}
David Kanarek's answer only works when you're manually creating your own UIImageView. If you've created a UIView and manually added it via Interface Builder then you will need a different approach like this calling the initWithCoder method instead.
I have the same problem, then I find it is.
I overwrite the init Method is -(id)initWithFrame:(CGRect)rect.
In this method self.background = [UIColor clearColor];
but i use this view in xib file !!! That will call the init method is
-(id)initWithCoder:(NSCoder*)aDecoder;
So overwrite all the init Method and setup BackgroundColor will work OK.
CGContextClearRect(context,rect)
If the provided context is a window or bitmap context, Quartz effectively clears the rectangle. For other context types, Quartz fills the rectangle in a device-dependent manner. However, you should not use this function in contexts other than window or bitmap contexts.
you can create a image context with this code:
cacheContext = CGBitmapContextCreate (cacheBitmap, size.width, size.height, 8, bitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);
CGContextSetRGBFillColor(cacheContext, 0, 0, 0, 0);
CGContextFillRect(cacheContext, (CGRect){CGPointZero, size});
the key is kCGImageAlphaPremultipliedLast.
Having trouble understanding the question here, but if you're unable to have a "background" UIView show through a "top" view into which you're drawing, one solution is topView.backgroundColor = [UIColor clearColor]; I was having (I think) this same problem and this solved it for me.