NSGradient into NSColor - objective-c

OK, long story short:
I'm using (embedded into the bundle) FontAwesome
I'm using it as the font in some custom NSButtons
In the NSButton subclass I want to colour them, exactly the way the Xcode tab items are coloured
This is how I'm setting the color (as a simple NSColor):
NSColor *color = [NSColor colorWithCalibratedRed:0.09 green:0.55 blue:0.90 alpha:1.0];
NSMutableAttributedString *colorTitle =
[[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
NSRange titleRange = NSMakeRange(0, [colorTitle length]);
[colorTitle addAttribute:NSForegroundColorAttributeName
value:color
range:titleRange];
[self setAttributedTitle:colorTitle];
How can I set it to an NSGradient?

OK, here's the solution, for anyone who may find useful...
Step 1:
Create a category on NSColor, based on the great answer by #Omz. In the code below, you'll see it renamed as colorFromGradient:, solely in order to mix well with the usual Cocoa naming conventions...
Step 2:
Redraw the title with the gradient color
NSColor* gS = [NSColor colorWithCalibratedRed:0.07 green:0.47 blue:0.87 alpha:1.0];
NSColor* gE = [NSColor colorWithCalibratedRed:0.12 green:0.64 blue:0.94 alpha:1.0];
NSGradient* g = [[NSGradient alloc] initWithStartingColor:gE endingColor:gS];
NSColor *color = [NSColor colorFromGradient:g];
NSMutableAttributedString *colorTitle =
[[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
NSRange titleRange = NSMakeRange(0, [colorTitle length]);
[colorTitle addAttribute:NSForegroundColorAttributeName
value:color
range:titleRange];
[self setAttributedTitle:colorTitle];
Step 3:
Enjoy the result. :-)

Related

How to change font in NSTextContainer

My application is setup as so.
Custom UIView inside a ScrollView.
The custom UIView is getting text generated on top of it with this code.
CoreDavening.m draw function
attStorage = [[NSTextStorage alloc]initWithAttributedString:string];
textContainer = [[NSTextContainer alloc]
initWithSize:CGSizeMake(self.frame.size.width, FLT_MAX)];
layoutManager = [[NSLayoutManager alloc]init];
[layoutManager addTextContainer:textContainer];
[attStorage addLayoutManager:layoutManager];
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer:textContainer];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];
In my ViewController.m I'm creating the view like so.
CoreDavening *davenView = [[CoreDavening alloc]initWithFrame:CGRectMake(0, 0,self.view.frame.size.width, [coreDavening heightForStringDrawing])];
davenView.backgroundColor = [UIColor whiteColor];
davenView.layer.borderColor = [[UIColor whiteColor]CGColor];
scrollView.backgroundColor = [UIColor whiteColor];
[scrollView addSubview:davenView];
self.scrollView.contentSize = davenView.frame.size;
Im trying to find a way to 1) change the font size (just size) 2) have the scrollView and CustomView resize appropriately.
How can this be done?
EDIT 1:
Im creating the custom view in my viewController like this.
CoreDavening *coreDavening = [[CoreDavening alloc]init];
davenView = [[CoreDavening alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, [coreDavening heightForStringDrawing ])];
and updating/refreshing the custom view like this.
It get triggered when the slider I have set up changes value.
- (IBAction)sliderChanged:(id)sender {
NSUserDefaults *prefs= [NSUserDefaults standardUserDefaults];
[prefs setInteger:(long)self.Slider.value forKey:#"fontSize"];
[prefs synchronize];
[davenView setNeedsLayout];
}
My custom view controller has the font set up like.
THIS IS IN THE DRAW FUNCTION
attStorage = [[NSTextStorage alloc]initWithAttributedString:string];
[attStorage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:(long)[prefs integerForKey:#"fontSize"]] range:NSMakeRange(0, attStorage.length)];
textContainer = [[NSTextContainer alloc]
initWithSize:CGSizeMake(self.frame.size.width, FLT_MAX)];
layoutManager = [[NSLayoutManager alloc]init];
[layoutManager addTextContainer:textContainer];
[attStorage addLayoutManager:layoutManager];
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer:textContainer];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];
It seems like you have the textStorage associated with the layoutManager already. NSTextStorage is the subclass of NSMutableAttributedString. So, this is the class which is responsible to hold the layout and styling information. How have you created your textStorage ? Besides, the styling, NSTextStorage also has methods to allow editing the contents and have dynamic styling.
You can simply set the attribute to your textStorage if you want to change the font.
[_textStorage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20.0] range:NSMakeRange(0, _textStorage.length)];
NSTextManager class has quite useful methods to find the bounds and glyphs informations. So, you could use method like below to find the bounds for your text,
- (CGRect)boundingRectWithSize:(CGSize)size
{
self.textContainer.size = size;
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
CGRect boundingRect = [self.layoutManager boundingRectForGlyphRange:glyphRange
inTextContainer:self.textContainer];
boundingRect.origin.x = 0;
boundingRect.origin.y = 0;
return boundingRect;
}

How to increase the font size of a NSAttributedsString in iOS

I am trying to change the font size of an NSAttributedString dynamically. The problem is the string contains different font sizes and properties. so when i change the font size all the content size change to tat value. Not changing accordingly . .. . .
If I understood you correctly this approach should help you: you can enumerate all NSFontAttributeName attributes for your AttributedString and increase the font size by for instance 1. This would give you the following result:
If that's what you want here is the code to achieve this
- (void)viewDidLoad
{
[super viewDidLoad];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0., 0., 320., 320.)];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.backgroundColor = [UIColor whiteColor];
self.label.numberOfLines = 0.;
NSString *text = #"Small medium large";
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, 6)];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(6, 7)];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:25] range:NSMakeRange(13, 5)];
self.label.attributedText = attributedText;
[self.view addSubview:self.label];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(bumpFontSize) userInfo:nil repeats:YES];
}
- (void)bumpFontSize
{
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.label.attributedText];
[self.label.attributedText enumerateAttributesInRange:NSMakeRange(0., self.label.text.length) options:NSAttributedStringEnumerationReverse usingBlock:
^(NSDictionary *attributes, NSRange range, BOOL *stop)
{
NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
UIFont *font = mutableAttributes[NSFontAttributeName];
UIFontDescriptor *fontProperties = font.fontDescriptor;
NSNumber *sizeNumber = fontProperties.fontAttributes[UIFontDescriptorSizeAttribute];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize: [sizeNumber floatValue] + 1.] range:range];
}];
self.label.attributedText = attributedText;
}

NSAttributedString drop shadow is cropping on descenders

I am using NSMutableAttributedString in iOS6 to apply kerning and drop shadows within a UILabel subclass. The attributes are being applied properly, however the drop shadow is cropping at at the left edge of the first character and the bottom of descenders ( lowercase p for example ). The label itself has clipsToBounds disabled.
The code...
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[self text]];
NSRange range = NSMakeRange(0, [attributedString length]);
NSNumber *kern = [NSNumber numberWithFloat:0.75f];
[attributedString addAttribute:NSKernAttributeName value:kern range:range];
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowBlurRadius:3.0f];
[shadow setShadowColor:[UIColor darkGrayColor]];
[shadow setShadowOffset:CGSizeMake(0, 2.0f)];
[attributedString addAttribute:NSShadowAttributeName value:shadow range:range];
[self setAttributedText:attributedString];
Its barely noticeable, but once you see it, it's obvious. Have others encountered this bug and is there a work-around?

NSAttributedString text position

I sub-classed a UILabel, so I can use this TitleLabel on several places. This TitleLabel has a custom font. The lineheight is set with an NSAttributedString.
This is the drawTextInRect override method:
- (void)drawTextInRect:(CGRect)rect {
self.text = #"THIS IS A TEST";
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:self.text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.minimumLineHeight = 15.f;
paragraphStyle.maximumLineHeight = 15.f;
[attStr addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:NSMakeRange(0,7)];
[attStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, self.text.length)];
[attStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:TITLE_FONT_NAME size:TITLE_FONT_SIZE] range:NSMakeRange(0, self.text.length)];
self.attributedText = attStr;
[super drawTextInRect:rect];
}
The background colors are added for test purposes. As you can see, the yellow background color has the right position. The text THIS IS should be in the yellow background, but is positioned above the background.
TITLE_FONT_SIZE is 15, defined somewhere else.
Anyone knows why this happens?
You are changing the font size, so that if the font is too big the text gets cut. That's normal, change your font size according to the rect size. Make it be something like this:
[attStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:TITLE_FONT_NAME size: MIN(rect.size.height*0.4,rect.size.width*0.4)] range:NSMakeRange(0, self.text.length)];
EDIT
Not sure which rectangle gets passed to the method. There's nothing in the doc, maybe is the frame and not the view bounds. Try this:
[super drawTextInRect: [self convertRect: rect fromView: nil] ];

How to add text shadows to a UITextView?

I've been searching around to find an easy way to add shadows to the text of a UITextView, like you can do in a UILabel. I found this question where there was an answer that supposedly does this, however, it makes no sense why this should be the case.
Question: Adding shadows to the layer of the UITextView itself should not affect the text inside, rather it should shadow the entire object, right?
In my case, even adding the shadow to the layer of the textview is not having any effect (even after adding the QuartzCore headers).
i tried, and found that , you should set the UITextView's backgroundcolor to transparent,
so the shadow should work
UITextView *text = [[[UITextView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)] autorelease];
text.layer.shadowColor = [[UIColor whiteColor] CGColor];
text.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
text.layer.shadowOpacity = 1.0f;
text.layer.shadowRadius = 1.0f;
text.textColor = [UIColor blackColor];
//here is important!!!!
text.backgroundColor = [UIColor clearColor];
text.text = #"test\nok!";
text.font = [UIFont systemFontOfSize:50];
[self.view addSubview:text];
#adali's answer will work, but its wrong. You shouldn't add the shadow to the UITextView itself in order to effect the visible views inside. As you can see, by applying the shadow to the UITextView the cursor will also have the shadow.
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.
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;