this is my first question on this message board so please go easy on me :)
A while ago I came across a useful piece of code to change a UILabel, this basically surounds the text in the label with a black (or an other color) outline.
- (void)drawTextInRect:(CGRect)rect; {
CGSize shadowOffset = self.shadowOffset;
UIColor *textColor = self.textColor;
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 2);
CGContextSetLineJoin(c, kCGLineJoinRound);
CGContextSetTextDrawingMode(c, kCGTextStroke);
self.textColor = [UIColor blackColor];
[super drawTextInRect:rect];
CGContextSetTextDrawingMode(c, kCGTextFill);
self.textColor = textColor;
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];
self.shadowOffset = shadowOffset;
}
I successfully used this as a good template to subclass my UILabels, and now I would say I have a fair understanding on subclassing.
What I would like to do is use this subclass as the UILabel part of a UIButton so that the text within my buttons have a matching black outline.
Any help or even just being pointed in the right direction would be greatly appreciated.
Thanks
Dave
Why not just subclass UIButton, and then within that subclass make the same changes you made in your UILabel subclass to the button's label property. Basically you would do everything the exact same way, except all of your changes would refer to self.titleLabel instead of just self.
Related
I've created a subview of UIView to make some drawings - the drawings work fine in the drawRect method of my subclass, however, I cannot change the background color of the view. A little googling tells me I haven't set the frame for the view, but I'm not entirely sure how to do this. I tried two things:
I create the view in Storyboard and add it to my view controller, then declare it as a property in the header file and link them up. I synthesize the property at the top of the implementation file and in the viewDidLoad method, I add:
[myView setBackgroundColor: [UIColor whiteColor]];
The view's background is still black.
I also tried:
ViewSubclass *v = [[ViewSubclass alloc] initWithFrame: self.view.frame];
v.backgroundColor = [UIColor whiteColor];
myView = v;
To no avail.
What am I doing wrong?
UPDATE: This is the code I use to draw in the view, in case there's something going on there!
- (void)drawRect:(CGRect)rect {
CGFloat height = self.bounds.size.height;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGFloat barWidth = 30;
int count = 0;
for (NSNumber *num in samples) {
CGFloat x = count * (barWidth + 10);
CGRect barRect = CGRectMake(x, height - ([num floatValue] * height), barWidth, [num floatValue] * height);
CGContextAddRect(context, barRect);
count++;
}
CGContextFillPath(context);
}
It just creates a set of bars in the screen, of different heights.
CGContextClearRect From the docs:
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.
It might be that this clearing clears your entire view with no regard to the background color you set
I can t add comments due my low lvl, but the question springs to mind, have you added to your UIView to viewcontroller?
like
[self.view addSubview:v];
EDIT:
I'm sorry I had understood that the second option was added to the view that pragmatically.
Are you adding the view in the header file? If so you might need to be sure the frame's coordinates are visible and that the view is on top, also make the new view slightly smaller to see if it is actually being created:
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
[self.view addSubview: myView];
[self.view bringSubviewToFront:myView];
You can also change the main view background color to see if the new view is actually being created. For example:
[self.view setBackgroundColor:[UIColor grayColor]];
If the color is changing for your main view then the problem is that your new view is not being or brought to the front. Let us know how it goes!
At the point where do
[myView setBackgroundColor: [UIColor whiteColor]];
check to see if myView is not nil in the debugger
I'm drawing text in -drawRect with this method:
[someText drawInRect:rect withFont:font lineBreakMode:someLineBreakMode alignment:someAlignment];
I just want to draw the outline but not the fill!
I've found that I can set CGContextSetFillColorWithColor and just provide an fully transparent color. But I fear this has bad performance impact because probably it does all the heavy drawing work behind the scenes with a transparent color.
Is there a way to just disable the fill-drawing if only outline-drawing is wanted?
Have you tried using kCGTextFillStroke? This might work easily. To use it, just override drawTextInRect
- (void)drawTextInRect:(CGRect)rect {
CGSize shadowOffset = self.shadowOffset;
UIColor *textColor = self.textColor;
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 1);
CGContextSetLineJoin(c, kCGLineJoinRound);
CGContextSetTextDrawingMode(c, kCGTextStroke);
self.textColor = [UIColor whiteColor];
[super drawTextInRect:rect];
CGContextSetTextDrawingMode(c, kCGTextFill);
self.textColor = textColor;
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];
self.shadowOffset = shadowOffset;
}
EDIT: This answer also appears in a previous incarnation of this question: How do I make UILabel display outlined text?
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 was wondering how the UILabel that displays the website's title in Mobile Safari is created? It's obviously some kind of a subclass and I've attempted to copy it by using my own subclass,but it just doesn't look the same. I also don't know which font they're using :/ Could anyone help me out please? :)
here's my class:
CGSize shadowOffset = self.shadowOffset;
UIColor *textColor = self.textColor;
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(c, 1);
CGContextSetTextDrawingMode(c, kCGTextStroke);
self.textColor = [UIColor grayColor];
[super drawTextInRect:rect];
CGContextSetTextDrawingMode(c, kCGTextFill);
self.textColor = textColor;
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];
self.shadowOffset = shadowOffset;
Looks like a basic UILabel with a shadow offset of (0, 1). The only hard part is finding the exactly font and colors that they use. I'm guessing it's just the boldSystemFont with a dark blue font color, and white shadow. You really don't need a subclass for this.
Edit:
UILabel: http://img823.imageshack.us/img823/1281/photo1w.png
Mobile Safari Comparison: http://img840.imageshack.us/img840/1538/photo2q.png
I just used the colors given in the interface builder, which are Tungsten (a dark gray) for the text, and Silver (a lighter gray) for the shadow.
I know soft shadows are not supported by the UILabel out of the box, on the iPhone. So what would be the best way to implement my own one?
EDIT:
Obviously I will subclass the UILabel and draw in the -drawRect:
My question is, how do I get the contents of the label as graphics and draw around them, blur them etc...
EDIT 2:
I returned to this question about a year later. In the meantime I've built a class that allows you to easily add soft shadow to a label and tweak it's radius etc and also to draw gradients on the text itself. You can find it on GitHub: https://github.com/doukasd/iOS-Components/tree/master/Views
As of 3.2 there is direct support for shadows in the SDK.
label.layer.shadowColor = [label.textColor CGColor];
label.layer.shadowOffset = CGSizeMake(0.0, 0.0);
#import <QuartzCore/QuartzCore.h> and play with some parameters:
label.layer.shadowRadius = 3.0;
label.layer.shadowOpacity = 0.5;
And, if you find your shadow clipped by the label bounds:
label.layer.masksToBounds = NO;
finally set
label.layer.shouldRasterize = YES;
I advise you to use the shadowColor and shadowOffset properties of UILabel:
UILabel* label = [[UILabel alloc] init];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0,1);
This answer to this similar question provides code for drawing a blurred shadow behind a UILabel. The author uses CGContextSetShadow() to generate the shadow for the drawn text.
Additionally to IIDan's answer:
For some purposes it is necessary to set
label.layer.shouldRasterize = YES
I think this is due to the blend mode that is used to render the shadow. For example I had a dark background and white text on it and wanted to "highlight" the text using a black shadowy glow. It wasn't working until I set this property.
Apply the (soft) shadow on the view's layer, like this:
UILabel *label = [[UIabel alloc] init];
label.layer.shadowColor = [[UIColor whiteColor] CGColor];
label.layer.shadowOpacity = 1.0;
To keep things up to date: Creating the shadow in Swift is as easy as that:
Import the QuartzCore Framework
import QuartzCore
And set the shadow attributes to your label
titleLabel.shadowColor = UIColor.blackColor()
titleLabel.shadowOffset = CGSizeMake(0.0, 0.0)
titleLabel.layer.shadowRadius = 5.0
titleLabel.layer.shadowOpacity = 0.8
titleLabel.layer.masksToBounds = false
titleLabel.layer.shouldRasterize = true
_nameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_nameLabel.font = [UIFont boldSystemFontOfSize:19.0f];
_nameLabel.textColor = [UIColor whiteColor];
_nameLabel.backgroundColor = [UIColor clearColor];
_nameLabel.shadowColor = [UIColor colorWithWhite:0 alpha:0.2];
_nameLabel.shadowOffset = CGSizeMake(0, 1);
i think you should use the [UIColor colorWithWhite:0 alpha:0.2] to set the alpha value.
I tried almost all of these techniques (except FXLabel) and couldn't get any of them to work with iOS 7. I did eventually find THLabel which is working perfectly for me. I used THLabel in Interface Builder and setup User Defined Runtime Attributes so that it's easy for a non programmer to control the look and feel.
https://github.com/MuscleRumble/THLabel
This like a trick,
UILabel *customLabel = [[UILabel alloc] init];
UIColor *color = [UIColor blueColor];
customLabel.layer.shadowColor = [color CGColor];
customLabel.layer.shadowRadius = 5.0f;
customLabel.layer.shadowOpacity = 1;
customLabel.layer.shadowOffset = CGSizeZero;
customLabel.layer.masksToBounds = NO;
I wrote a library that provides a UILabel subclass with soft shadow support and a bunch of other effects:
https://github.com/nicklockwood/FXLabel
In Swift 3, you can create an extension:
import UIKit
extension UILabel {
func shadow() {
self.layer.shadowColor = self.textColor.cgColor
self.layer.shadowOffset = CGSize.zero
self.layer.shadowRadius = 3.0
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false
self.layer.shouldRasterize = true
}
}
and use it via:
label.shadow()
Subclass UILabel, as stated, then, in drawRect:, do [self drawTextInRect:rect]; to get the text drawn into the current context. Once it is in there, you can start working with it by adding filters and whatnot. If you want to make a drop shadow with what you just drew into the context, you should be able to use:
CGContextSetShadowWithColor()
Look that function up in the docs to learn how to use it.
As of iOS 5 Apple provides a private api method to create labels with soft shadows.
The labels are very fast: I'm using dozens at the same time in a series of transparent views and there is no slowdown in scrolling animation.
This is only useful for non-App Store apps (obviously) and you need the header file.
$SBBulletinBlurredShadowLabel = NSClassFromString("SBBulletinBlurredShadowLabel");
CGRect frame = CGRectZero;
SBBulletinBlurredShadowLabel *label = [[[$SBBulletinBlurredShadowLabel alloc] initWithFrame:frame] autorelease];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.font = [UIFont boldSystemFontOfSize:12];
label.text = #"I am a label with a soft shadow!";
[label sizeToFit];
While it's impossible to set a blur radius directly on UILabel, you definitely could change it by manipulating CALayer.
Just set:
//Required properties
customLabel.layer.shadowRadius = 5.0 //set shadow radius to your desired value.
customLabel.layer.shadowOpacity = 1.0 //Choose an opacity. Make sure it's visible (default is 0.0)
//Other options
customLabel.layer.shadowOffset = CGSize(width: 10, height: 10)
customLabel.layer.shadowColor = UIColor.black.cgColor
customLabel.layer.masksToBounds = false
What I hope will help someone and other answers failed to clarify is that it will not work if you also set UILabel Shadow Color property directly on Interface Builder while trying to setup .layer.shadowRadius.
So if setting label.layer.shadowRadius didn't work, please verify Shadow Color for this UILabel on Interface Builder. It should be set to default. And then, please, if you want a shadow color other than black, set this color also through .layer property.
Subclass UILabel, and override -drawInRect: