bold, italic using UIFontDescriptor - ios

i have an UITextView that have some text and 2 buttons one to make selected texet bold anthor to make it italic
- (IBAction)boldedSelectedText:(UIButton*)sender {
UIFontDescriptor* bodyFontDescriptor=[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
UIFontDescriptor* boldFontdescriptor=[bodyFontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
self.body.font=[UIFont fontWithDescriptor:boldFontdescriptor size:0.0];
}
- (IBAction)italicSelectedText:(UIButton *)sender {
UIFontDescriptor* bodyFontDescriptor=[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
UIFontDescriptor* italicFontdescriptor=[bodyFontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
self.body.font=[UIFont fontWithDescriptor:italicFontdescriptor size:0.0];
}
the problem is when i select a text and make it bold then italic , it become italic only and vice
it can not be bold and italic at the same time i don't know why?

You need to retrieve the existing symbolic traits first, then add your new trait.
I use a helper method to add/remove my traits,
-(void) addOrRemoveFontTraitWithName:(NSString*)traitName andValue:(uint32_t)traitValue
{
NSMutableDictionary *attributes;
NSRange selectedRange=[self.attributedTextview selectedRange];
if (selectedRange.length == 0)
{
//no text selected
attributes=[[NSMutableDictionary alloc] initWithDictionary:self.attributedTextview.typingAttributes];
}
else
{
attributes=[[NSMutableDictionary alloc] initWithDictionary:[self.attributedTextview.textStorage attributesAtIndex:selectedRange.location effectiveRange:nil]];
}
UIFont *currentFont=[attributes objectForKey:NSFontAttributeName];
UIFontDescriptor *fontDescriptor=[currentFont fontDescriptor];
NSString *fontNameAttribute=[[fontDescriptor fontAttributes] objectForKey:UIFontDescriptorNameAttribute];
UIFontDescriptor *changedFontDescriptor;
if ([fontNameAttribute containsString:traitName])
{
uint32_t existingTraitsWithNewTrait=[fontDescriptor symbolicTraits] | traitValue;
changedFontDescriptor=[fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithNewTrait];
}
else
{
uint32_t existingTraitsWithoutTrait=[fontDescriptor symbolicTraits] & ~traitValue;
changedFontDescriptor=[fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithoutTrait];
}
UIFont *updatedFont=[UIFont fontWithDescriptor:changedFontDescriptor size:0.0];
[attributes setObject:updatedFont forKey:NSFontAttributeName];
if (selectedRange.length != 0)
{
[self.attributedTextview.textStorage beginEditing];
[self.attributedTextview.textStorage setAttributes:attributes range:selectedRange];
[self.attributedTextview.textStorage endEditing];
}
[self.attributedTextview setTypingAttributes:attributes];
}
If the user has selected some text, the trait is applied to that specific selection, otherwise it is applied to the textview's typingAttributes property.
A bitwise operation is required to add/remove the trait.
This article covers this subject in some detail and is well worth a read
Using Text Kit to Manage and Draw Text in IOS Apps
Regards

Related

Multiple fonts inside a single UITextField

I have a TextField and three buttons which are 40pts above the TextField. These buttons provide the changing of font size of TextField's text when I clicked on any of them for eg first button set font size to 17 second changes it to 20 and third change it to 24. So I add IbAction to all buttons like
- (IBAction)setRegularText:(id)sender {
self.additionalInfo.font = [UIFont systemFontOfSize:20];
}
And according to button. But it will change the previous entered text too. I want the text font to be change only when user selet the option. Previously entered text's font size must not be changed.
You will need to use the attributed string NSAttributedString. With text field it is best to have a delegate and implement the method on changing the characters in range. This will handle all the cases even when the user pasts the text from somewhere else.
So the NSMutableAttributedString has a method to replace the string in range with a mutable attributed string which is perfect for this method. The new string received by the delegate must simply be converted to the attributed one with a currently set font.
Try something like this:
#interface AttributedTextField : NSObject<UITextFieldDelegate>
#property (nonatomic, strong) NSMutableAttributedString *attributedString;
#property (nonatomic, strong) UIFont *currentFont;
#end
#implementation AttributedTextField
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// ensure having a font
UIFont *font = self.currentFont;
if(font == nil) {
font = [UIFont systemFontOfSize:12.0f];
}
// ensure having a base string
if(self.attributedString == nil) {
self.attributedString = [[NSMutableAttributedString alloc] initWithString:#""];
}
// append the new string
[self.attributedString replaceCharactersInRange:range withAttributedString:[[NSMutableAttributedString alloc] initWithString:string attributes:#{NSFontAttributeName: font}]];
textField.attributedText = self.attributedString; // assign the new text which is attributed
return NO; // return false as we are overriding the text
}
#end
set the tag of every button as the font size that button should change.
i-e
self.button1.tag = 17;
self.button2.tag = 20;
self.button3.tag = 24;
and use the tag as font size.
i-e
- (IBAction)setRegularText:(UIButton *)sender {
self.additionalInfo.font = [UIFont systemFontOfSize:sender.tag];
}
You can set different text size in textfield like this way:
- (void)setFontString:(NSString *)setString setFontSize: (double) fontSize {
self.txtAnswer.text = #"";
self.txtAnswer.text = setString;
self.txtAnswer.font = [UIFont systemFontOfSize:fontSize];
}
- (IBAction)btn1Tap:(id)sender {
[self setFontString:#"Good Morning" setFontSize:20.0f];
}
- (IBAction)btn2Tap:(id)sender {
[self setFontString:#"Good Afternoon" setFontSize:15.0f];
}
- (IBAction)btn3Tap:(id)sender {
[self setFontString:#"Good Evening" setFontSize:10.0f];
}

how to make font bold,unbold of any font style

Can anybody please explain how can we make any font family font, bold or unbold + Italic or Non Italic + Underlined or Non underLined. Everywhere I got the method that make the changes but on system font. I even tried giving 2 attributes to NSAttributed string
1. Bold
2. A font family from list of supported font family
But it didnt work. Thanks in Advance.
try this
UIFontDescriptor *fontDescriptor = [[UIFontDescriptor alloc] init];
UIFontDescriptor *fontDescriptorForHelveticaNeue = [fontDescriptor fontDescriptorWithFamily:#"Helvetica Neue"];
UIFontDescriptor *symbolicFontDescriptor = [fontDescriptorForHelveticaNeue fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
UIFontDescriptor *symbolicFontDescriptor1 = [fontDescriptorForHelveticaNeue fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitMonoSpace];
NSString *text = #"iOS 7";
if(some condition){
CGSize fontSize = [text sizeWithAttributes:#{NSFontAttributeName:[UIFont fontWithDescriptor:symbolicFontDescriptor size:17.0f]}];
}
else{
CGSize fontSize = [text sizeWithAttributes:#{NSFontAttributeName:[UIFont fontWithDescriptor:symbolicFontDescriptor1 size:17.0f]}];
}
You can't do it with a few lines of code. A normal font and its bold version are completely separated (ie they're like two unrelated fonts), and if you have a look at iosfonts, the naming is not consistent. Some fonts don't have bold version, and some have several bold versions!
A solution (that requires a bit of effort, but surely works): create a list of pairs of font names, like this
{"ArialHebrew", "ArialHebrew-Bold"},
{"AvenirNext-Regular", "AvenirNext-Bold"},
...
And populate the list of fonts with the regular version (the left one). If the user desires to make it bold, then switch to the bold version (the right one).
My recommendation is to limit the number of choices for user (as iOS always does): you don't need to copy the whole list from iosfonts! just some popular ones are enough.
This may not be sufficiently generic for your purses, but maybe it'll help someone else
+ (UIFont *)whateverInvertedBoldnessFontFromFont:(UIFont *)font pointSize:(CGFloat)pointSize
{
NSString *customFontFamilyName = #"Whatever";
NSString *ibFontName = font.fontName;
NSString *customFontStyle = nil;
if ([ibFontName rangeOfString:#"Bold"].location != NSNotFound) {
customFontStyle = #"Regular";
}
else {
customFontStyle = #"Bold";
}
UIFont *customFont = [UIFont fontWithName:[NSString stringWithFormat:#"%#-%#", customFontFamilyName, customFontStyle] size:pointSize];
return customFont;
}
unfortunately this is quite fragile and works reliably when the source and destination
font families are known
If you want to set it programmatically, you must check with the font supported by xCode (iOS).
and if you want to do bold to any font then you have to use :
UIFont* boldFont = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[myLabel setFont:boldFont];
where myLabel is your label name.

How do I create a bold UIFont from a regular UIFont?

If I have a UIFont object, is it possible to convert it to bold? I don't know the font name, I just have a UIFont object. What I want is a function like
UIFont *boldFontFromFont(UIFont *input)
{
return [input derivedFontWithFontWeight:UIFontWeightBold];
}
How can I change the code so that it works. (The code above does not work, I just made it up to illustrate the point.)
Thanks in advance.
iOS 7 introduces a new UIFontDescriptor class, which makes it a lot easier:
UIFont *font = [UIFont fontWithName:#"Helvetica Neue" size:12];
NSLog(#"plain font: %#", font.fontName); // “HelveticaNeue”
UIFont *boldFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold] size:font.pointSize];
NSLog(#"bold version: %#", boldFont.fontName); // “HelveticaNeue-Bold”
UIFont *italicFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic] size:font.pointSize];
NSLog(#"italic version: %#", italicFont.fontName); // “HelveticaNeue-Italic”
UIFont *boldItalicFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic] size:font.pointSize];
NSLog(#"bold & italic version: %#", boldItalicFont.fontName); // “HelveticaNeue-BoldItalic”
For people who got here looking for a Cocoa (macOS) equivalent, UIFontDescriptor comes from NSFontDescriptor, available since 10.3.
And if you are looking for the swift implementation:
let normalFont = UIFont(name: "FONT_NAME", size: CGFloat(20))!
let boldFont = UIFont(descriptor: normalFont.fontDescriptor.withSymbolicTraits(.traitBold)!, size: normalFont.pointSize)
Hope this helps! Cheers!
To get a bold font you need to pass a specific name of the font from a font family. You can get a font family name from a given font, then list all fonts from this family. In general, a bold font will contain "bold" in its name, but the format isn't strict and there could be variations like "Helvetica-BoldOblique", for example. You can start from this code:
- (UIFont *)boldFontFromFont:(UIFont *)font
{
NSString *familyName = [font familyName];
NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
for (NSString *fontName in fontNames)
{
if ([fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
UIFont *boldFont = [UIFont fontWithName:fontName size:font.pointSize];
return boldFont;
}
}
return nil;
}
This is a very old thread but someone may be interested in how to do this in Swift 5 nowadays.
Easy like this:
var font: UIFont = UIFont.systemFont(ofSize: 18)
if let newDescriptor = font.fontDescriptor.withSymbolicTraits(.traitBold) {
font = UIFont(descriptor: newDescriptor, size: font.pointSize)
}
Attempting to derive the bold/italic font using font or family names no longer works correctly since iOS 7, due to the cryptic font family name of the system font. Below is a simple extension to derive the bold/italic font using the UIFontDescriptor class.
+(UIFont *) font:(UIFont *)font bold:(BOOL)bold italic:(BOOL)italic
{
NSUInteger traits = 0;
if (bold)
{
traits |= UIFontDescriptorTraitBold;
}
if (italic)
{
traits |= UIFontDescriptorTraitItalic;
}
return [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:traits] size:font.pointSize];
}
You can either use
[UIFont boldSystemFontOfSize:12].
If you are using custom fonts you have to use the name directly
[UIFont fontWithName:#"Helvetica-Bold" size:17.0].
You can look up the possible font names with
[UIFont fontNamesForFamilyName:#"American Typewriter"].
In this Post: https://stackoverflow.com/a/15388946/436818 Ben M has an idea how to get the bold version dynamically. But extend the method to be sure to get the bold version (if it exists) because there are other bold versions like CondensedBold too.
Since this question pops up when you search for bold UIFonts in Swift, here's a fresh answer:
extension UIFont {
/// Returns a new font in the same family with the given symbolic traits,
/// or `nil` if none found in the system.
func withSymbolicTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
guard let descriptorWithTraits = fontDescriptor.withSymbolicTraits(traits)
else { return nil }
return UIFont(descriptor: descriptorWithTraits, size: 0)
}
}
Example:
myFont.withSymbolicTraits(.taitBold) // returns the bold version of myFont
Nobody posted a solution which:
is for Swift
is an extension for UIFont
doesn't do force unwraps
uses the same point size as source font
and only does what is asked in the question (create bold UIFont based on existing UIFont)
so I'm doing it:
import UIKit
extension UIFont {
func boldFont() -> UIFont? {
guard let boldDescriptor = fontDescriptor.withSymbolicTraits(.traitBold) else {
return nil
}
return UIFont(descriptor: boldDescriptor, size: pointSize)
}
}
Feel free to copy-and-paste!

How to tell which iOS font name is the "regular" version in a font family?

I know that I can get a list of font family names with [UIFont familyNames] and iterate through the family's font names with [UIFont fontNamesForFamilyName:]. Is there any way to tell which font name represents the "normal" font? There isn't any consistency in the naming ("Roman", "Regular", or even the absence of a modifier adjective). I'm ultimately trying to change the font over a substring of an NSAttributedString while maintaining existing traits and decorations. Thanks in advance.
Well, I need to read the CoreText docs more closely. Passing in the font family name is enough if you use the right CoreText routines...
NSString *fontFamilyName = ...(font family name)...;
// Make a mutable copy of the attributed text
NSMutableAttributedString *workingAttributedText = [self.attributedText mutableCopy];
// Over every attribute run in the selected range...
[workingAttributedText enumerateAttributesInRange:self.selectedRange
options:(NSAttributedStringEnumerationOptions) 0
usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
// get the old font
CTFontRef oldFont = (__bridge CTFontRef)[attrs objectForKey:NSFontAttributeName];
// make a new one, with our new desired font family name
CTFontRef newFontRef = CTFontCreateCopyWithFamily(oldFont, 0.0f, NULL, (__bridge CFStringRef)fontFamilyName);
// Convert it to a UIFont
UIFont *newFont = [UIFont fontWithCTFont:newFontRef];
// Add it to the attributed text
[workingAttributedText addAttribute:NSFontAttributeName value:newFont range:range];
}];
// Replace the attributed text with the new version
[self setAttributedText:workingAttributedText];
If there is an easier way to do this, I'd love to hear about it.
There doesn't have to be a regular font in the list. Some may only provide bold or only italic. This is why the list is often provided to the user to let them make the decision.

How to make a UIFont bold or italic?

Having a UILabel with any font, how can I find out if it is already bold? Or how can I make it bold? In CSS, I have a font-weight attribute. I would like to have something similar.
Everything I found out so far is that you have to set the proper font name. However, this is unreliable. The bold version of Cochin is Cochin-Bold, but the bold version of ArialMT is not ArialMT-Bold but Arial-BoldMT, so it obviously does not suffice to append -Bold. (The bold version of a custom font could also have a totally different name).
What I can do is finding all fonts for the family of my given font.
__block UIFont *font = myLabel.font;
[[UIFont fontNamesForFamilyName:font.familyName] enumerateObjectsUsingBlock:^(NSString *fontName, NSUInteger idx, BOOL *stop) {
if ([fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location != NSNotFound) {
font = [UIFont fontWithName:fontName size:font.pointSize];
*stop = YES;
}
}];
myLabel.font = font;
But this does not work reliably. I can easily get a BoldItalic version. I could improve my check to avoid this, but it is not really a good solution.
Maybe CoreText can help here?
Maybe CoreText can help here?
CoreText uses its own font system, CTFont. If you're using that, you can do what you want:
CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)name, size, NULL);
CTFontRef boldFont = CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontBoldTrait, kCTFontBoldTrait);
I suppose you could then get the name of the derived bold font:
CFStringRef boldName = CTFontCopyPostScriptName(boldFont);
...and use it to create a new UIFont:
UIFont *ret = [UIFont fontWithName:(NSString *)boldName size:size];
I don't know how quick this would be, but you could do it on app launch then cache the names.
Introduced with iOS 7, UIFontDescriptor is the tool for doing this.
To find out if the font is already bold, get the UIFontDescriptor of your font (via UIFont's fontDescriptor property), then call symbolicTraits, and inspect the resulting bitmask for UIFontDescriptorTraitBold.
Likewise, to find a bold version, take the font descriptor for the original font, and call - fontDescriptorWithSymbolicTraits:. You can then turn it back into a UIFont by calling + [UIFont fontWithDescriptor:size:].
UIFontDescriptorSymbolicTraits symbolically describes stylistic aspects of a font. The upper 16 bits is used to describe appearance of the font whereas the lower 16 bits for typeface. The font appearance information represented by the upper 16 bits can be used for stylistic font matching.
Swift 3
extension UIFont {
convenience init?(name: String, size: CGFloat, symbolicTraits: UIFontDescriptorSymbolicTraits) {
guard let descriptor = UIFontDescriptor(name: name, size: size).withSymbolicTraits(symbolicTraits) else { return nil }
self.init(descriptor: descriptor, size: size)
}
}

Resources