문제

I want to an UITextView to switch between two display modes. In mode 1 it should show abbreviations and in the full word in mode 2. For example "Abbr." vs "abbreviation".

What would be the best way to do this? Keeping in mind that some words can have the same abbreviation and that the user is free to type either the full word or the abbreviation?

So far I tried to subclass NSLayoutManager. Assuming I get an abbreviated string and I have to draw the full word, I would implement the following method:

-(void)setGlyphs:(const CGGlyph *)glyphs
  properties:(const NSGlyphProperty *)props
characterIndexes:(const NSUInteger *)charIndexes
        font:(UIFont *)aFont
 forGlyphRange:(NSRange)glyphRange
{
    NSUInteger length = glyphRange.length;
    NSString *sourceString = @"a very long string as a source of characters for substitution"; //temp.

unichar *characters = malloc(sizeof(unichar) * length+4);
CGGlyph *subGlyphs = malloc(sizeof(CGGlyph) * length+4);
[sourceString getCharacters:characters
                      range:NSMakeRange(0, length+4)];

CTFontGetGlyphsForCharacters((__bridge CTFontRef)(aFont),
                             characters,
                             subGlyphs,
                             length+4);

[super setGlyphs:subGlyphs
      properties:props
characterIndexes:charIndexes
            font:aFont
   forGlyphRange:NSMakeRange(glyphRange.location, length+4)];   

}

However this method complains about invalid glyph indices "_NSGlyphTreeInsertGlyphs invalid char index" when I try to insert 4 additional glyphs.

도움이 되었습니까?

해결책

You're barking way up the wrong tree; trying to subclass NSLayoutManager in this situation is overkill. Your problem is merely one of swapping text stretches (replace abbrev by original or original by abbrev), so just do that - in the text, the underlying NSMutableAttributedString being displayed.

You say in a comment "some words map to the same abbreviation". No problem. Assuming you know the original word (the problem would not be solvable if you did not), store that original word as part of the NSMutableAttributedString, i.e. as an attribute in the place where the word is. Thus, when you substitute the abbreviation, the attribute remains, and thus the original word is retained, ready for you when you need to switch it back.

For example, given this string: @"I love New York" You can hide the word "New York" as an attribute in the same stretch of text occupied by "New York":

[attributedString addAttribute:@"realword" value:@"New York" range:NSMakeRange(7,8)];

Now you can set that range's text to @"NY" but the attribute remains, and you can consult it when the time comes to switch the text back to the unabbreviated form.

(I have drawn out this answer at some length because many people are unaware that you are allowed to define your own arbitrary NSAttributedString attributes. It's an incredibly useful thing to do.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top