4

我正在用 Core Text 制作杂志,并尝试自动在文本中添加连字符。我想我可以用这个功能做到这一点

CFStringGetHyphenationLocationBeforeIndex

但它不起作用,我在网上找不到任何例子。

我要做的是设置文本,如果我发现任何连字符位置,我会在此处放置一个“-”并通过访问器替换文本,以便它调用 setNeedsDisplay 并从头开始重新绘制。

- (void) setTexto:(NSAttributedString *)texto {

    _texto = texto;

    if (self.ctFrame != NULL) {
        CFRelease(self.ctFrame);
        self.ctFrame = NULL;
    }

    [self setNeedsDisplay];
}

-(void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, self.bounds);
    CTFramesetterRef ctFrameSetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(_texto));
    self.ctFrame = CTFramesetterCreateFrame(ctFrameSetterRef, CFRangeMake(0, [_texto length]), path, NULL);

    NSArray *lines = (__bridge NSArray *)(CTFrameGetLines(self.ctFrame));

    CFIndex lineCount = [lines count];
    NSLog(@"lines: %d", lines.count);

    for(CFIndex idx = 0; idx < lineCount; idx++) {

        CTLineRef line = CFArrayGetValueAtIndex((CFArrayRef)lines, idx);

        CFRange lineStringRange = CTLineGetStringRange(line);
        NSRange lineRange = NSMakeRange(lineStringRange.location, lineStringRange.length);

        NSString* lineString = [self.texto.string substringWithRange:lineRange];

        CFStringRef localeIdent = CFSTR("es_ES");
        CFLocaleRef localeRef = CFLocaleCreate(kCFAllocatorDefault, localeIdent);

        NSUInteger breakAt = CFStringGetHyphenationLocationBeforeIndex((__bridge CFStringRef)lineString, lineRange.length, CFRangeMake(0, lineRange.length), 0, localeRef, NULL);

        if(breakAt!=-1) {
            NSRange replaceRange = NSMakeRange(lineRange.location+breakAt, 0);
            NSMutableAttributedString* attributedString = self.texto.mutableCopy;
            [attributedString replaceCharactersInRange:replaceRange withAttributedString:[[NSAttributedString alloc] initWithString:@"-"]];
            self.texto = attributedString.copy;
            break;
        } else {
            CGFloat ascent;
            CGFloat descent;
            CTLineGetTypographicBounds(line, &ascent, &descent, nil);
            CGContextSetTextPosition(context, 0.0, idx*-(ascent - 1 + descent)-ascent);
            CTLineDraw(line, context);
        }
    }
}

问题是它第二次进入drawRect(带有新文本)lines.count log 为0。而且我不确定这是正确的方法。

也许还有另一种修改 CTLines 的方法(在上一行的“-”之后添加剩余的字符)。

4

1 回答 1

7

在创建属性字符串之前,您可以添加软连字符。那你就可以画图了。

我编写了一个类别,用于向任何字符串添加“软连字符”。这些是“-”,在渲染时不可见,而只是排队等待 CoreText 或 UITextKit 知道如何分解单词。

NSString *string = @"accessibility tests and frameworks checking";
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
NSString *hyphenatedString = [string softHyphenatedStringWithLocale:locale error:nil];
NSLog(@"%@", hyphenatedString);

输出ac-ces-si-bil-i-ty tests and frame-works check-ing


NSString+SoftHyphenation.h

typedef enum {
    NSStringSoftHyphenationErrorNotAvailableForLocale
} NSStringSoftHyphenationError;

extern NSString * const NSStringSoftHyphenationErrorDomain;
extern NSString * const NSStringSoftHyphenationToken;

@interface NSString (SoftHyphenation)

- (BOOL)canSoftHyphenateStringWithLocale:(NSLocale *)locale;
- (NSString *)softHyphenatedStringWithLocale:(NSLocale *)locale error:(out NSError **)error;

@end

NSString+SoftHyphenation.m

#import "NSString+SoftHyphenation.h"

NSString * const NSStringSoftHyphenationErrorDomain = @"NSStringSoftHyphenationErrorDomain";
NSString * const NSStringSoftHyphenationToken = @"­"; // NOTE: UTF-8 soft hyphen!

@implementation NSString (SoftHyphenation)

- (BOOL)canSoftHyphenateStringWithLocale:(NSLocale *)locale
{
    CFLocaleRef localeRef = (__bridge CFLocaleRef)(locale);
    return CFStringIsHyphenationAvailableForLocale(localeRef);
}

- (NSString *)softHyphenatedStringWithLocale:(NSLocale *)locale error:(out NSError **)error
{
    if(![self canSoftHyphenateStringWithLocale:locale])
    {
        if(error != NULL)
        {
            *error = [self hyphen_createOnlyError];
        }
        return [self copy];
    }
    else
    {
        NSMutableString *string = [self mutableCopy];
        unsigned char hyphenationLocations[string.length];
        memset(hyphenationLocations, 0, string.length);
        CFRange range = CFRangeMake(0, string.length);
        CFLocaleRef localeRef = (__bridge CFLocaleRef)(locale);

        for(int i = 0; i < string.length; i++)
        {
            CFIndex location = CFStringGetHyphenationLocationBeforeIndex((CFStringRef)string, i, range, 0, localeRef, NULL);

            if(location >= 0 && location < string.length)
            {
                hyphenationLocations[location] = 1;
            }
        }

        for(int i = string.length - 1; i > 0; i--)
        {
            if(hyphenationLocations[i])
            {

                [string insertString:NSStringSoftHyphenationToken atIndex:i];
            }
        }

        if(error != NULL) { *error = nil; }

        // Left here in case you want to test with visible results
        // return [string stringByReplacingOccurrencesOfString:NSStringSoftHyphenationToken withString:@"-"];
        return string;
    }
}

- (NSError *)hyphen_createOnlyError
{
    NSDictionary *userInfo = @{
                               NSLocalizedDescriptionKey: @"Hyphenation is not available for given locale",
                               NSLocalizedFailureReasonErrorKey: @"Hyphenation is not available for given locale",
                               NSLocalizedRecoverySuggestionErrorKey: @"You could try using a different locale even though it might not be 100% correct"
                               };
    return [NSError errorWithDomain:NSStringSoftHyphenationErrorDomain code:NSStringSoftHyphenationErrorNotAvailableForLocale userInfo:userInfo];
}

@end

希望这可以帮助 :)

于 2013-11-08T11:58:38.877 回答