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;
Related
I am customizing my UITableView and I figured out how to set the selected color of each cell. In my cellForRowAtIndexPath method, I have the following code:
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor orangeColor]];
[cell setSelectedBackgroundView:bgColorView];
[bgColorView release];
But it is a solid orange. I want to make it more slick looking, and have it be a slight gradient from light orange to darker orange. How can I do this?
You'd use Core Graphics (a.k.a. Quartz) to draw a gradient in your view's -drawRect: method:
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat colors[8] = {1.0, 0.75, 0.30, 0.5, 0.7, 0.2, 1.0, 0.8};
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(space, colors, NULL, 2);
CGContextDrawLinearGradient(ctx, gradient, top, bottom, NULL);
You can limit the area that the gradient fills by creating a path in the current context (ctx) and the clipping to it using CGContextClip(ctx);. top and bottom are CGPoints that define the beginning and end of the gradient.
You will have to override the view's drawRect method to draw the gradient. It can be kind of a PIA, but you can also check out this open source component which may work:
http://cocoacontrols.com/platforms/ios/controls/gradient-view
#Caleb's answer is right on; I do this for a variety of things.
What no one has mentioned is that the view for which you need to implement drawRect: is a custom UITableViewCell.
simple google search will find your answer ....
http://bluesplat-tech.blogspot.com/2009/03/gradient-shading-uiview.html
If you want a complex or subtle gradient, you can set a background image that is partial alpha and set the cell background color to change appearance.
I know title of my question is so bad, but I don't know how to describe it.
When an UIAlertView pops up, anything else on the screen (except the UIAlertView) becomes a bit darker but can be seen. I call this as Focus effect, because you will know clearly and directly that now the UIAlertView is the focus.
So how can I implement such a focus effect?
thanks
Just add a translucent view below the view you want to "focus" on.
Simple example:
UIView *shieldView = [[[UIView alloc] initWithFrame:myView.bounds] autorelease];
shieldView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.7];
[myView.superview insertSubview:shieldView belowSubview:myView];
UIAlertView actually uses an image with a radial gradient instead of a simple color, in order to highlight the center of the view.
I know this post is a bit old but I thought it might help someone.
Use this code to generate the radial gradient background:
- (UIImage *)radialGradientImage:(CGSize)size start:(float)start end:(float)end centre:(CGPoint)centre radius:(float)radius{
UIGraphicsBeginImageContextWithOptions(size, YES, 1);
size_t count = 2;
CGFloat locations[2] = {0.0, 1.0};
CGFloat components[8] = {start, start, start, 1.0, end, end, end, 1.0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef grad = CGGradientCreateWithColorComponents (colorSpace, components, locations, count);
CGColorSpaceRelease(colorSpace);
CGContextDrawRadialGradient (UIGraphicsGetCurrentContext(), grad, centre, 0, centre, radius, kCGGradientDrawsAfterEndLocation);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(grad);
UIGraphicsEndImageContext();
return image;}
Define gradient in the .h file like so:
UIImageView *gradient;
Call your gradient like so:
- (void)addGradient{
CGSize size = self.view.bounds.size;
CGPoint centre = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
float startColor = 1.0f;
float endColor = 0.0f;
float radius = MIN(self.view.bounds.size.width/4, self.view.bounds.size.height/4);
gradient = [[UIImageView alloc] initWithImage:[self radialGradientImage:size
start:startColor
end:endColor
centre:centre
radius:radius]];
[gradient setBackgroundColor:[UIColor clearColor]];
[gradient setUserInteractionEnabled:YES];
[gradient setAlpha:0.6f];
[self.view addSubview:gradient];}
UIAlertView works like this. It fades in an alpha mask image to dim out the background. Once that animation is finished it starts the "bounce in" animation of the dialog.
So to reproduce it you need first to generate an alpha mask with a "bright spot" where your dialog will end up and fade that in. Then use a (few) frame animation(s) to get the bounce effect.
More info here: Creating a Pop animation similar to the presentation of UIAlertView
To make it better than "not good" you could ...
create a UIView in a nib (easiest if the part of your code where you need the effect is already utilising a nib) and then add a translucent graphic (with a 'focus' effect) to that view.
connect the UIView in the nib to an IBOutlet
fade in the graphic using an animation into view hierarchy (omz example shows this)
This question already has answers here:
Inner shadow effect on UIView layer?
(17 answers)
Closed 9 years ago.
I want to apply inner-shadow to a UILabel. I have a solution, but it's not good enough. Anyone with a better solution?
// UILabel subclass
- (void) drawTextInRect:(CGRect)rect {
CGSize myShadowOffset = CGSizeMake(0, 2);
float myColorValues[] = {255, 0, 0, 1};
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(myContext);
CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues);
CGContextSetShadowWithColor (myContext, myShadowOffset, 5, myColor);
CGContextSetBlendMode(myContext, kCGBlendModeLighten);
[super drawTextInRect:rect];
CGColorRelease(myColor);
CGColorSpaceRelease(myColorSpace);
CGContextRestoreGState(myContext);
}
I'm familiar with the layer property of UILabel, but shadow offset gives us a outer-shadow, NOT inner-shadow (unless i'm missing something).
Borrowing on Ruben's answer above, if you do the reverse ie. set your text color equal to your background color (with low alpha) and then set the shadow to be a stronger color, it creates a decent inset effect. Here's what I mean (Note: My view background is white):
cell.textLabel.textColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5];
cell.textLabel.shadowColor = [UIColor darkGrayColor];
cell.textLabel.shadowOffset = CGSizeMake(-1.0,-1.0);
[cell.textLabel setText:#"Welcome to MyApp!"];
and this is the output
This would probably only work on very light backgrounds as I suspect it will create unwanted overlay on darker backgrounds.
You can ofcourse vary the shadowOffset to change the direction of light.
I tried to do this but finally opted to use the default shadowOffset and play with the shadowColor to give the inner drop shadow effect to the text. In small texts it gives you a good inner shadow effect. For example, if you have a grayColor background and apply a whiteColor to the shadow, then you have an acceptable inner shadow effect.
Sometimes, it's better to design those texts with graphic tools and make localized copies if needed.
Answer here : Inner Shadow in UILabel Long code but it seems to work
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.
I need to create a custom UILabel to display some dynamic multiline text. The text color is white on a black background. But the background should only be visible right behind the text to simulate the effect of an selected text area.
I started with subclassing UILabel and overriding drawTextInRect to do my own drawings.
- (void) drawTextInRect:(CGRect)rect
{
/* do some custom drawings here */
[super drawTextInRect:rect];
}
So far i could not figure out a way to compute the text-bounds do draw my background into.
Does anybody now how do do this kind of stuff? Thanks a lot.
NSString has some additions in UIKit to allow for calculating the size used to render the string, given various parameters. You can use these methods to calculate the size the UILabel needs to render the string, and then resize the UILabel to precisely this size. Look in the documentation for a method called -sizeWithFont:, all of the other variations are listed there. Make sure you use the right method to match how your UILabel is configured.
There is one caveat here, which is that on iOS 4, there is a bug where these methods actually return a slightly different size than is actually used for drawing (at least for the system font on iPhone 4's [e.g. Helvetica Neue], I don't know if this bug affects any other fonts). Unfortunately the only workaround I know of is to switch to Core Text for all your text rendering, so you may just prefer to live with this bug (if it even affects you) until Apple pushes out a software update. This bug does affect Apple's own applications so there is plenty of precedent for not handling it.
Ok. Now after some input from stackoverflow i am using this code snippet to get the textbounds but it only works fine with single line text.
- (void) drawTextInRect:(CGRect)rect
{
CGFloat lineHeight = [self.text sizeWithFont:self.font].height;
CGSize testSize = CGSizeMake(320, lineHeight * self.numberOfLines);
CGSize textSize = [self.text sizeWithFont:self.font constrainedToSize:testSize lineBreakMode:self.lineBreakMode];
//NSLog(#"drawTextInRect lineHeight %f, width %f x height %f", lineHeight, textSize.width, textSize.height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextAddRect(context, CGRectMake(0, 0, textSize.width, textSize.height));
CGContextFillPath(context);
CGContextRestoreGState(context);
[super drawTextInRect:rect];
}
If i have multiline text i still need some code to compute the path-information of the text and not just the bounding rect so that i can use CGContextDrawPath to draw my background. Any thoughts on that? Thanks.