I'm trying to add a shadow to a UITableViewCell using the layer.shadowColor, Offset, Radius but it doesn't seem to affect it in any way. The table is grouped style. Any ideas why?
Here is the code i'm using:
cell.layer.shadowColor= [UIColor blackColor].CGColor;
cell.layer.shadowRadius = 5.0;
cell.layer.shadowOffset = CGSizeMake(10, 10);
You need to also set the shadow opacity, it defaults to 0 and you won't see anything if you don't explicitly set it.
CALayer Reference
cell.layer.shadowOffset = CGSizeMake(1, 0);
cell.layer.shadowColor = [[UIColor blackColor] CGColor];
cell.layer.shadowRadius = 5;
cell.layer.shadowOpacity = .25;
Also note, that if you don't set the shadow path you will have terrible performance on the iPhone/iPad. Use something like the following code to set a shadow path, it removes the need to blur the layers underneath your tableviewcell's to create a "high quality" shadow.
CGRect shadowFrame = cell.layer.bounds;
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
cell.layer.shadowPath = shadowPath;
Watch video 425 (also 424 and 426) to learn more about shadows from the WWDC 2010 Videos available here: WWDC 2010 Session Videos
Just adding the #Paul Soult answer in Swift:
cell?.layer.shadowOffset = CGSizeMake(0, 1)
cell?.layer.shadowColor = UIColor.blackColor().CGColor
cell?.layer.shadowRadius = 1
cell?.layer.shadowOpacity = 0.6
// Maybe just me, but I had to add it to work:
cell?.clipsToBounds = false
let shadowFrame: CGRect = (cell?.layer.bounds)!
let shadowPath: CGPathRef = UIBezierPath(rect: shadowFrame).CGPath
cell?.layer.shadowPath = shadowPath
The view hierarchy of a grouped table view cell is really rather opaque. cell.layer is actually referring to the layer of the main view of the cell, which takes of the entire width of the table. The rounded part of the cell that is inset is actually handled by apple's private methods for drawing grouped cells.
You're probably going to have more luck creating a custom subclass of UITableViewCell.
Related
if I use layer.shadow like this:
self.layer.shadowOffset = CGSizeMake(0, 1.5);
self.layer.shadowColor = [UIColor grayColor].CGColor;
self.layer.shadowOpacity = 1;
and put some(not more than 10) of these views(without images) into a UIScrollView,
it makes the scrollView very slow when is scrolling.
if I remove any codes about shadow, scrolling become quite smooth again.
FYI, the un-smooth case happen when running the app on iOS device,
but smooth on iOS simulator.
Does any one know how to keep both shadow and smooth scrolling?
It will help if you set a shadow path and set the should rasterize flag on the layer.
Something like this:
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
self.layer.shadowPath = [path CGPath];
self.layer.shouldRasterize = YES;
i have a scroll view loaded with 3 view controllers. each view controller is drawing its layers with that code -
(there us more then that but I pulled it out to check if it will help). still i have very crappy sliding.
any help ?
shani
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [Helper cardBackGroundColor:card].CGColor;
sublayer.shadowOffset = CGSizeMake(0, 3);
sublayer.shadowRadius = 5.0;
sublayer.shadowColor = [UIColor blackColor].CGColor;
sublayer.shadowOpacity = 0.8;
sublayer.frame = CGRectInset(self.view.layer.frame, 20, 20);
sublayer.borderColor = [UIColor blackColor].CGColor;
sublayer.borderWidth = 2.0;
sublayer.cornerRadius = 10.0;
[self.view.layer addSublayer:sublayer];
Drawing things with CALayer often yields poor performance. We usually use a stretchable image to get adequate performance. When you think of it, it does make sense to render it before hand rather than using the iPhone's limited processing power to render it in real time.
It's possible that you can get adequate performance from CALayer, but drawing a png will probably still be faster, thus saving battery life time.
EDIT: So here's an example to explain the concept.
This code actually replaced a CALayer drawing that was too slow.
UIImageView *shadow = [[UIImageView alloc] initWithFrame:frame];
shadow.image = [[UIImage imageNamed:#"shadow.png"] stretchableImageWithLeftCapWidth:16.0 topCapHeight:16.0];
[contentView addSubview:shadow];
[shadow release];
shadow.png is 34 by 34 pixels and contains a shadowed square. Thanks to the stretchable image it's possible to resize the square without stretching the shadow. For more information about this I would suggest reading the documentation for stretchableImageWithLeftCapWidth:topCapHeight:. Also Google will help you find guides on how to work with stretchable images. If you have more questions I'll be happy to answer them.
You have a mask (assuming you somewhere say masksToBounds=YES) and a shadow on this layer. Both cause an off screen rendering pass.
Please watch the WWDC 2010 Session 425 - Core Animation in Practice Part 2
Which you can find here;
http://developer.apple.com/videos/wwdc/2010/
What is the proper way to implement shadows with CoreGraphics? I've looked around but haven't been able to find a whole lot on it. Is there a simple method for adding a shadow to a view, or will I have to subclass and override the drawRect: method?
You can also use CALayer shadows on any existing view, but the performance penalty is terrible. I don't recommend doing it, especially if you are supporting older devices.
view.layer.shadowOffset = CGSizeMake(2.0, 2.0);
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowRadius = 3.0;
view.layer.shadowOpacity = 1.0;
See Quartz 2D Programing Guide: Shadows. Basically, you call CGContextSetShadow(CGContextRef context, CGSize shadowSize, CGFloat blurValue) and then do your drawing.
Is it possible to add a shadow to the text in a UITextField?
As of 3.2, you can use the CALayer shadow properties.
_textField.layer.shadowOpacity = 1.0;
_textField.layer.shadowRadius = 0.0;
_textField.layer.shadowColor = [UIColor blackColor].CGColor;
_textField.layer.shadowOffset = CGSizeMake(0.0, -1.0);
I have a slightly different problem - I want a blurred shadow on a UILabel. Luckily, the solution to this turned out to be number (2) from Tyler
Here's my code :
- (void) drawTextInRect:(CGRect)rect {
CGSize myShadowOffset = CGSizeMake(4, -4);
CGFloat myColorValues[] = {0, 0, 0, .8};
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(myContext);
CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues);
CGContextSetShadowWithColor (myContext, myShadowOffset, 5, myColor);
[super drawTextInRect:rect];
CGColorRelease(myColor);
CGColorSpaceRelease(myColorSpace);
CGContextRestoreGState(myContext);
}
This is in a class that extends from UILabel and draws the text with a shadow down and to the right 4px, the shadow is grey at 80% opacity and is sightly blurred.
I think that Tyler's solution number 2 is a little better for performance than Tyler's number 1 - you're only dealing with one UILabel in the view and, assuming that you're not redrawing every frame, it's not a hit in rendering performance over a normal UILabel.
PS This code borrowed heavily from the Quartz 2D documentation
I don't think you get built-in support for text shadows here, the way you do with UILabel.
Two ideas:
(1) [Moderately tricky to code.] Add a second UITextField behind the original, at a very small offset (maybe by (0.2,0.8)? ). You can listen to every text change key-by-key by implementing the textField:shouldChangeCharactersInRange:replacementString: method in the UITextFieldDelegate protocol. Using that, you can update the lower text simultaneously. You could also make the lower text (the shadow text) gray, and even slightly blurry using the fact that fractionally-offset text rects appear blurry. Added: Oh yea, don't forget to set the top text field's background color to [UIColor clearColor] if you go with this idea.
(2) [Even more fun to code.] Subclass UITextField and override the drawRect: method. I haven't done this before, so I'll mention up front that this depends on this being the designated drawing method, and it may turn out that you have to override another drawing function, such as drawTextInRect:, which is specific to UITextField. Now set up the drawing context to draw shadows via the CGContextSetShadow functions, and call [super drawRect:rect];. Hopefully that works -- in case the original UITextField code clears the drawing context's shadow parameters, that idea is hosed, and you'll have to write the whole drawing code yourself, which I anti-recommend because of all the extras that come with UITextFields like copy-and-paste and kanji input in Japanese.
Although the method of applying the shadow directly to the UITextView will work, it's the wrong way to do this. By adding the shadow directly with a clear background color, all subviews will get the shadow, even the cursor.
The approach that should be used is with NSAttributedString.
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:textView.text];
NSRange range = NSMakeRange(0, [attString length]);
[attString addAttribute:NSFontAttributeName value:textView.font range:range];
[attString addAttribute:NSForegroundColorAttributeName value:textView.textColor range:range];
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor whiteColor];
shadow.shadowOffset = CGSizeMake(0.0f, 1.0f);
[attString addAttribute:NSShadowAttributeName value:shadow range:range];
textView.attributedText = attString;
However textView.attributedText is for iOS6. If you must support lower versions, you could use the following approach. (Dont forget to add #import <QuartzCore/QuartzCore.h>)
CALayer *textLayer = (CALayer *)[textView.layer.sublayers objectAtIndex:0];
textLayer.shadowColor = [UIColor whiteColor].CGColor;
textLayer.shadowOffset = CGSizeMake(0.0f, 1.0f);
textLayer.shadowOpacity = 1.0f;
textLayer.shadowRadius = 0.0f;
i would like to draw a border / shadow around a uiscrollview, i know that i could get there with an additional view or scrollview but dont like the handling an drawbacks but i heard that there should be a possibility to dirctly draw a border to a scrollview and that is what i would prefer.
I am quiet new to iphone developement,any answer would helpful.
If you use the layer property of your scroll view (or any UIView) you can easily get a solid border...
#import <QuartzCore/QuartzCore.h>
...
myView.layer.borderWidth = 2;
myView.layer.borderColor = [UIColor blackColor].CGColor;
You can also use the layer to apply real-time shadows by setting the layer.shadow* properties, but performance can be slow with this technique, so I generally prefer to use the following more complex, but more performant technique. You can create a PNG image with transparency in the middle and shadows around the edge - it needs to have 9 distinct areas: 4 for each corner, 4 for each edge, and a completely transparent 1x1 pixel area in the middle. For example if your shadow extends 6 pixels into your image, your image would be 13x13 with the 6 pixel wide/high borders and the 1x1 area in the middle. Then you set it as a scalable image using:
newImage = [image stretchableImageWithLeftCapWidth:6 topCapHeight:6];
UPDATE: Since iOS 5.0 stretchableImageWithLeftCapWidth:topCapHeight: is deprecated so only use this if you still want to support iOS 4.x devices. If you want to support only iOS 5.0+ devices use this instead:
newImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(6, 6, 6, 6)];
Then you put the image on the parent view so it takes up the entire area of the scroll view. If you want the shadows to go OVER your scrollable elements, (so your scroll view looks inset/behind the rest of the page) then place a transparent UIView over the top with the shadow image on it so that it shows through to your scroll view behind it.
Dont forget to:
#import <QuartzCore/QuartzCore.h>
If you want to use
myView.layer.borderWidth = 2;
myView.layer.borderColor = [UIColor blackColor].CGColor;
To get the CGColorRef from an UIColor you can also use this example:
myView.layer.borderWidth = 2;
myView.layer.borderColor = [UIColor blackColor].CGColor;
myView.layout.borderColor generates an incompatible pointer warning when using UIColor, and did not change the border for me.
Using CGColorRef worked for me instead:
CGFloat lComponents[4] = {0,0,0,1};
CGColorSpaceRef lColorSpace = CGColorSpaceCreateDeviceRGB();
myView.layer.borderColor = CGColorCreate(lColorSpace, lComponents);
CGColorSpaceRelease(lColorSpace);