iphone - Focus effect (just like UIAlertView) - iphone

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)

Related

divide image into two parts using divider

I'm working on one app where I need to divide a image into two part using a red line.
left part for labels
right part for prices
Question 1.
How can I draw a red line on image?
Question 2.
How can I divide image to two parts using red line ?( red line position is not fixed. user can move the position wherever it want)
Question 3.
How can I get line current position and how can I use that position two divide image
Thanks in advance
I would approach this in somewhat the same manner as koray was suggesting:
1) I am assuming that your above image/view is going to be managed by a view controller, which I will call ImageSeperatorViewController from here on.
Inside of ImageSeperatorViewController, insert koray's code in the -(void) viewDidLoad{} method. Make sure you change the imageToSplit variable to be an UIImageView instead of a plain UIView.
2) Next, I assume that you know how to detect user gestures. You will detect these gestures, and determine if the user has selected the view (i.e. bar in koray's code). Once you have determined if the user has selected bar, just update its origin's X position with the touch position.
CGRect barFrame = bar.frame;
barFrame.origin.x = *X location of the users touch*
bar.frame = barFrame;
3) For cropping, I would not use github.com/bilalmughal/NLImageCropper, it will not do what you need to do.
Try this on for size:
Header:
#interface UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor*)color;
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage;
- (NSArray*)imagesBySlicingAt:(CGFloat)position;
#end
Implementation:
#implementation UIImage (ImageDivider)
- (UIImage*)imageWithDividerAt:(CGFloat)position patternImage:(UIImage*)patternImage
{
//pattern image
UIColor *patternColor = [UIColor colorWithPatternImage:patternImage];
CGFloat width = patternImage.size.width;
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color from the pattern image color
CGContextSetFillColorWithColor(context, patternColor.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//the joy of image color patterns being based on 0,0 origin! must set phase
CGContextSetPatternPhase(context, CGSizeMake(dividerRect.origin.x, 0));
//fill the divider rect with the repeating pattern from the image
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)imageWithDividerAt:(CGFloat)position width:(CGFloat)width color:(UIColor *)color
{
//set up context
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//set the fill color for your divider
CGContextSetFillColorWithColor(context, color.CGColor);
//this is your divider's area
CGRect dividerRect = CGRectMake(position - (width / 2.0f), 0, width, self.size.height);
//fill the divider's rect with the provided color
CGContextFillRect(context, dividerRect);
//get your new image and viola!
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (NSArray*)imagesBySlicingAt:(CGFloat)position
{
NSMutableArray *slices = [NSMutableArray array];
//first image
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointZero];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
//second
{
//context!
UIGraphicsBeginImageContext(CGSizeMake(self.size.width - position, self.size.height));
//draw the existing image into the context
[self drawAtPoint:CGPointMake(-position, 0)];
//get your new image and viola!
[slices addObject:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
}
return slices;
}
The concept is simple - you want an image with the divider drawn over it. You could just overlay a view, or override drawRect:, or any number of any solutions. I'd rather give you this category. It just uses some quick Core Graphics calls to generate an image with your desired divider, be it pattern image or color, at the specified position. If you want support for horizontal dividers as well, it is rather trivial to modify this as such. Bonus: You can use a tiled image as your divider!
Now to answer your primary question. Using the category is rather self explanatory - just call one of the two methods on your source background to generate one with the divider, and then apply that image rather than the original source image.
Now, the second question is simple - when the divider has been moved, regenerate the image based on the new divider position. This is actually a relatively inefficient way of doing it, but this ought to be lightweight enough for your purposes as well as only being an issue when moving the divider. Premature optimization is just as much a sin.
Third question is also simple - call imagesBySlicingAt: - it will return an array of two images, as generated by slicing through the image at the provided position. Use them as you wish.
This code has been tested to be functional. I strongly suggest that you fiddle around with it, not for any purpose of utility, but to better understand the mechanisms used so that next time, you can be on the answering side of things
For Crop you can try this,
UIImage *image = [UIImage imageNamed:#"yourImage.png"];
CGImageRef tmpImgRef = image.CGImage;
CGImageRef topImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, 0, image.size.width, image.size.height / 2.0));
UIImage *topImage = [UIImage imageWithCGImage:topImgRef];
CGImageRelease(topImgRef);
CGImageRef bottomImgRef = CGImageCreateWithImageInRect(tmpImgRef, CGRectMake(0, image.size.height / 2.0, image.size.width, image.size.height / 2.0));
UIImage *bottomImage = [UIImage imageWithCGImage:bottomImgRef];
CGImageRelease(bottomImgRef);
hope this can help you, :)
if you want to draw a line you could just use a UIView with red background and make the height the size of your image and the width around 5 pixels.
UIView *imageToSplit; //the image im trying to split using a red bar
CGRect i = imageToSplit.frame;
int x = i.origin.x + i.size.width/2;
int y = i.origin.y;
int width = 5;
int height = i.size.height;
UIView *bar = [[[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)] autorelease];
bar.backgroundColor = [UIColor redColor];
[self.view addSubview:bar];

Image mask without transparant part

I've been looking into this for a while now.
I'm trying to put a gray image over a cup
Currently i'm stretching an uiimageview with a grey background to the amount the slider has gone.
-(void) sliderChanged:(CGFloat) value{
drinksView.grayArea.frame = CGRectMake( 0 , -value ,372 ,value);
I know this is very dirty ,not what i want...
What i want is that the grey part only covers the part where there is a cup (e.g the part where the image is not transparant). The image of the cup just has a transparant background
Does anybody have an idea of how to achieve this ? i'm a noob with masks and many tutorials have led me nowhere and i don't even know if it's possible.
P.S: drawing a path around the cup is not possible because the cup image can change to a glass
The easiest way I can think of is to use a masked CALayer. This is what you need to do:
Instead of using a UIImageView, use a CALayer with gray background as your overlay. Your sliderChanged: method would remain untouched, except that drinksView.grayArea would be a layer instead of a view.
So far the effect will be exactly the same as before. Now, you need to set the grayArea's mask. Do the following:
CALayer * maskLayer = [CALayer new];
maskLayer.contents = myCupImage.CGImage;
grayArea.mask = maskLayer;
I think by default the layer will stretch the content as the scale is changed. We don't want that. You can fix this by setting the layer's contentsGravity to, say, kCAGravityTop.
That should do what you want.
One caveat: I'm not quite sure how masks cope with changing content gravity. If you have issues on that front, you can fixed it by adding a container layer:
Set a fixed frame for grayArea (equal to the size of the cup image).
Instead of adding grayArea directly, introduce a container layer for it:
CALayer * container = [CALayer new];
container.masksToBounds = YES;
[container addSublayer:grayArea];
[drinksView.layer addSublayer:container];
In your sliderChanged:, change the frame of container instead of the grayArea.
Hope this works.
First of all you will need to get familiar with this method
// masks the item based on the MaskImage
- (UIImage*) itemMask : (UIImage*)image withMask:(UIImage*)maskImage
{
UIImage* afterMasking = nil;
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
CFRelease(mask);
afterMasking = [UIImage imageWithCGImage:masked];
CFRelease(masked);
return afterMasking;
}
What that does is that you feed it your Cup image and the mask Image together and it will mask your cup image. It will only mask your cup image and nothing underneath so you don't have to worry.
The problem you have is that the grey box resizes. How I would approach this is to crop the mask according to the slider value. So make a black box and change it size how you do with the grayBG BEFORE you feed it through the method. That should be quick to do so so I won't elaborate but at the end you will have something like this. Pardon the half elaborated graphics
drinksView.grayLayer = [CALayer new];
drinksView.grayLayer.frame = CGRectMake(0, 0, 372, 0);
drinksView.grayLayer.contentsGravity = kCAGravityTop;
CALayer * topLayer = [CALayer new];
topLayer.frame = CGRectMake(0, 0, 372, 367);
UIImage * grayImage = [UIImage imageNamed:#"grayDrink.png"];
topLayer.contents = (id) grayImage.CGImage;
CALayer * maskLayer = [CALayer new];
maskLayer.contents = (id)cupImage.CGImage;
maskLayer.masksToBounds = YES;
maskLayer.bounds = CGRectMake(0, 0, 372, 367);
maskLayer.position = CGPointMake(186,184);
[topLayer setMask:maskLayer];
[drinksView.grayLayer addSublayer:topLayer];
[drinksView.grayLayer setMasksToBounds:YES];
[[drinksView layer]addSublayer:drinksView.grayLayer];

ios unread message icon

I was wondering if there is a standard method in iOS to produce the numbered bubble icon for unread messages as the ones used in mail for iphone and mac.
I'm not talking about the red dots on the application item which is done with badgevalue but about the blue bubble beside the mailboxes.
Of course one can do it manually using coregraphics but it's harder to match the dimensions and color of the standard ones used in mail etc.
here are three ways to do this, in order of difficulty..
screen shot your mail app from your iphone, send the image into photoshop, extract the blue dot and use it as an image in your app. To use it in a tableviewcell, you just set the imageView.image = [UIImage imageName:#"blueDot.png"];
same as #1, except save the image as a grayscale, this way you can use Quartz and overlay your own colors on top of it. so you can make that dot any color you want. Very cool stuff.
Use Quartz to draw the whole thing. Its really not that hard. Let me know if you would like some code for that.
OK, twist my arm... here is the code to draw your own gradient sphere... from quartz.
Make a class that inherits from UIView. add the following code
static float RADIANS_PER_DEGREE=0.0174532925;
-(void) drawInContext:(CGContextRef) context
{
// Drawing code
CGFloat radius = self.frame.size.width/2;
CGFloat start = 0 * RADIANS_PER_DEGREE;
CGFloat end = 360 * RADIANS_PER_DEGREE;
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(0, self.bounds.size.height);
//define our grayscale gradient.. we will add color later
CGFloat cc[] =
{
.70,.7,.7,1, //r,g,b,a of color1, as a percentage of full on.
.4,.4,.4,1, //r,g,b,a of color2, as a percentage of full on.
};
//set up our gradient
CGGradientRef gradient;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(rgb, cc, NULL, sizeof(cc)/(sizeof(cc[0])*4));
CGColorSpaceRelease(rgb);
//draw the gray gradient on the sphere
CGContextSaveGState(context);
CGContextBeginPath(context);
CGContextAddArc(context, self.bounds.size.width/2, self.bounds.size.height/2, radius,start,end , 0);
CGContextClosePath(context);
CGContextClip(context);
CGContextAddRect(context, self.bounds);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation);
CGGradientRelease(gradient);
//now add our primary color. you could refactor this to draw this from a color property
UIColor *color = [UIColor blueColor];
[color setFill];
CGContextSetBlendMode(context, kCGBlendModeColor); // play with the blend mode for difference looks
CGContextAddRect(context, self.bounds); //just add a rect as we are clipped to a sphere
CGContextFillPath(context);
CGContextRestoreGState(context);
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawInContext:context];
}
If you want to use a graphic resource from iOS, you can find it using the UIKit-Artwork-Extractor tool. Extract everything to the desktop and find the one you want. For example, the red badge for notifications is called SBBadgeBG.png. I don't know which one you mean, so search for it yourself :P
This is what I did to use a badge, the procedure is exactly the same to show a bubble in a subview of your table:
// Badge is an image with 14+1+14 pixels width and 15+1+15 pixels height.
// Setting the caps to 14 and 15 preserves the original size of the sides, so only the pixel in the middle is stretched.
UIImage *image = [UIImage imageNamed:#"badge"];
self.badgeImage = [image stretchableImageWithLeftCapWidth:(image.size.width-1)/2 topCapHeight:(image.size.height-1)/2];
// what size do we need to show 3 digits using the given font?
self.badgeFont = [UIFont fontWithName:#"Helvetica-Bold" size:13.0];
CGSize maxStringSize = [[NSString stringWithString:#"999"] sizeWithFont:self.badgeFont];
// set the annotation frame to the max needed size
self.frame = CGRectMake(0,0,
self.badgeImage.size.width + maxStringSize.width,
self.badgeImage.size.height + maxStringSize.height);
and then override the method drawRect: of your view to paint the badge and the numbers inside:
- (void)drawRect:(CGRect)rect {
// get the string to show and calculate its size
NSString *string = [NSString stringWithFormat:#"%d",self.badgeNumber];
CGSize stringSize = [string sizeWithFont:self.badgeFont];
// paint the image after stretching it enough to acommodate the string
CGSize stretchedSize = CGSizeMake(self.badgeImage.size.width + stringSize.width,
self.badgeImage.size.height);
// -20% lets the text go into the arc of the bubble. There is a weird visual effect without abs.
stretchedSize.width -= abs(stretchedSize.width *.20);
[self.badgeImage drawInRect:CGRectMake(0, 0,
stretchedSize.width,
stretchedSize.height)];
// color of unread messages
[[UIColor yellowColor] set];
// x is the center of the image minus half the width of the string.
// Same thing for y, but 3 pixels less because the image is a bubble plus a 6px shadow underneath.
float height = stretchedSize.height/2 - stringSize.height/2 - 3;
height -= abs(height*.1);
CGRect stringRect = CGRectMake(stretchedSize.width/2 - stringSize.width/2,
height,
stringSize.width,
stringSize.height);
[string drawInRect:stringRect withFont:badgeFont];
}

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 same 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:
Determine the rect for the foreground view.
Convert the rect in the foreground view to a rect in the background view.
Begin a new graphics context.
Draw the background with the proper blend mode.
Draw the foreground with the proper blend mode.
Extract the image from the graphics context.
End the graphics context.
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.

Drop Shadow on UITextField text

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;