Find attributes from attributed string that user typed

后端 未结 1 1933
你的背包
你的背包 2020-12-01 15:14

In my app the User will type anything that he wants and he can make the text Bold, Italic and Underline.

I am able to do the Text - Bold, Italic a

相关标签:
1条回答
  • 2020-12-01 16:07

    You can enumerate the Attributes with this code (whole range).

    [attrStr enumerateAttributesInRange:NSMakeRange(0, [attrStr length]) options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:
             ^(NSDictionary *attributes, NSRange range, BOOL *stop) {
    //Do something here
                 }
             }];
    

    For specific range, your have to change the code NSMakeRange(0, [attrStr lenght]) by the range you need.

    After your edit, your specific need, this code should do the work:

    [attrStr enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
                                options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
                             usingBlock:
     ^(NSDictionary *attributes, NSRange range, BOOL *stop)
    {
         NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
         UIFont *currentFont = [mutableAttributes objectForKey: NSFontAttributeName];
         UIFont *newFont;
         if ([[currentFont fontName] isEqualToString:@"Calibri-BoldItalic"])
             newFont = [UIFont fontWithName:@"HelveticaNeue-BoldItalic" size:currentFont.pointSize];
         else if ([[currentFont fontName] isEqualToString:@"Calibri-Bold"])
             newFont = [UIFont fontWithName:@"HelveticaNeue-Bold" size:currentFont.pointSize];
         else if ([[currentFont fontName] isEqualToString:@"Calibri-Italic"])
             newFont = [UIFont fontWithName:@"HelveticaNeue-Italic" size:currentFont.pointSize];
        [mutableAttributes setObject:newFont forKey:@"NSFont"];
        [attrStr setAttributes:mutableAttributes range:range];
     }];
    

    From your comments, you may see more complicated things, so I will give you some ideas/tips to do/check. You'll just have to complete my previous code to manage all cases.
    • Case: There is no font.
    You just have to check if currentFont is nil. If yes, you set what you want. Since there is no attribute for italic/bold (since they are "included" in the font), I suggest you set for newFont: HelveticaNeue.
    • Case: It's another font than Calibri. There it's quite more complicated.
    I've worked with that, and here what I got: Font name (which is the postscript name) is made like this for HelveticaNeue (as given example):

    HelveticaNeue
    HelveticaNeue-Light
    HelveticaNeue-UltraLight
    HelveticaNeue-Medium
    HelveticaNeue-LightItalic
    HelveticaNeue-Italic
    HelveticaNeue-UltraLightItalic
    HelveticaNeue-Bold
    HelveticaNeue-BoldItalic
    HelveticaNeue-CondensedBold
    HelveticaNeue-CondensedBlack

    So the first thing you could think of: I just have to check the suffix of the name (with hasSuffix:). But that may go wrong.
    Indeed, some fonts have a foundry suffix (the ones I found are LT, MT, and EF).
    Well, for example:
    Times New Roman "real name" is TimesNewRomanPSMT.
    And its italic version is TimesNewRomanPS-ItalicMT
    That's why we have to check if it has a foundry suffix because TimesNewRomanPSMT-Italic won't work (since it doesn't exist, if you try to set a font with this name, it will be nil).
    So, as far as I know, and as far I may have some experience and the case I've seen, what you could do: Check if the [currentFont name] contains either: BoldItalic, Italic or Bold, using a NSRegularExpression or a rangeOfString:. Note that I'd suggest to check before for BoldItalic since an Italic may "hides" a Bold just before it, and Bold may "hides" an Italic just after it.
    In order to do so, I'd suggest that you create a method like this (or of this style):

    -(UIFont)getCorrespondingHelveticaNeueFontMatchingCharacteriticsOf:(UIFont *)font
    {
        UIFont *helveticaNueue;
        if (!font) //Checking if there is a font)
        {
            helveticaNueue = [UIFont fontWithName@"HelveticaNueue" size:defaultSizeYouSet];
        }
        else
        {
            //Check if it's BoldItalic/Italic/Bold
        }
        return helveticaNueue;
    }
    

    checking all the case I mentioned before.
    So, from the previous code, you'll just have to replace the if tests that were working specificly for Calibri with:

    UIFont *newFont = [self getCorrespondingHelveticaNeueFontMatchingCharacteriticsOf:currentFont];
    

    Now a third part you may want to do (and add them to your test): Is the Black case of a font want to be managed as Bold? Well, Helvetica Neue has this "property", but you may want to use directly the black property for Helvetica Neue, and may want to check if currentFont has it (and again, another case).

    EDIT: You can use since iOS7 we can use UIFontDescriptor. Here is what you could do:

    -(UIFont *)customFontMatchingFont:(UIFont *)otherFont
    {
        NSString *customFontName = @"Helvetica"; //The custom font
        UIFont *tempFont = [UIFont fontWithName:customFontName size:[otherFont pointSize]]; 
        return [UIFont fontWithDescriptor:[[tempFont fontDescriptor] fontDescriptorWithSymbolicTraits:[[otherFont fontDescriptor] symbolicTraits]] size:[otherFont pointSize]];
    }
    

    Note: I didn't check all the cases (what if your custom family doesn't have a matching font, what does it return? etc.), but that could be a nice add-on if you don't do too complicated things.

    0 讨论(0)
提交回复
热议问题