2013-01-01 53 views
11

語境如何統一縮放NSTextView中的豐富文本?

我有一個使用一個NSTextView富文本輸入一個正常的基於文檔的可可的Mac OS X應用程序。用戶可以編輯NSTextView中文本的字體系列,磅值大小和顏色。

基地SDK:10.7
部署目標:10.6


問題:

我想實現整個UI的變焦編程(包括NSTextView),同時用戶正在編輯文本。縮放NSTextView的幀是沒有問題的。但是我不知道如何縮放視圖中的可編輯文本,該文本可能在整個文本運行的不同子節中包含多個不同的點大小。

如何將統一比例因子應用於顯示在NSTextView中的富文本?

這應該與「富文本」,使得用戶的字體,顏色尤其是點大小(這可能是在文字的運行的不同位置有不同)將被保留,但均勻縮放/相對發揮很好。

這是可能給我的基本SDK和部署目標?是否可以使用較新的基本SDK或部署目標?

+2

難道你可能需要10.8起來,利用10.8的內置文本縮放的?如果您可以要求10.8並且文本不必包裝到縮放區域,這可能是一種前進的方式。請參閱TextEdit的視圖>縮放...菜單項。 –

回答

10

如果意圖是縮放視圖(而不實際更改字符串中的屬性),我會建議使用scaleUnitSquareToSize:method:以及ScalingScrollView(與TextEdit示例代碼一起提供)以獲得正確的滾動條行爲。

從ScalingScrollView其核心部件是:

- (void)setScaleFactor:(CGFloat)newScaleFactor adjustPopup:(BOOL)flag 
{ 
CGFloat oldScaleFactor = scaleFactor; 
    if (scaleFactor != newScaleFactor) 
    { 
     NSSize curDocFrameSize, newDocBoundsSize; 
     NSView *clipView = [[self documentView] superview]; 

     scaleFactor = newScaleFactor; 

     // Get the frame. The frame must stay the same. 
     curDocFrameSize = [clipView frame].size; 

     // The new bounds will be frame divided by scale factor 
     newDocBoundsSize.width = curDocFrameSize.width/scaleFactor; 
     newDocBoundsSize.height = curDocFrameSize.height/scaleFactor; 
    } 
    scaleFactor = newScaleFactor; 
    [scale_delegate scaleChanged:oldScaleFactor newScale:newScaleFactor]; 
} 

scale_delegate是您的委託,它可以調整你的NSTextView對象:

- (void) scaleChanged:(CGFloat)oldScale newScale:(CGFloat)newScale 
{ 
    NSInteger  percent = lroundf(newScale * 100); 

    CGFloat scaler = newScale/oldScale; 
    [textView scaleUnitSquareToSize:NSMakeSize(scaler, scaler)]; 

    NSLayoutManager* lm = [textView layoutManager]; 
    NSTextContainer* tc = [textView textContainer]; 
    [lm ensureLayoutForTextContainer:tc]; 
} 

scaleUnitSquareToSize:方法尺度相對於其目前的狀態,所以你跟蹤您的比例因子,然後將您的絕對比例要求(200%)轉換爲相對比例要求。

+0

謝謝,很多很好的信息在這裏!完成後,我會深入並更新我的迴應。 –

+0

更新:這正是我需要的信息。我能夠使用'-scaleUnitSquareToSize:'方法來實現我想要的。謝謝馬克! –

1

OP在這裏。

我發現了一種解決方案,它可以工作,而且不是非常難以實現。但我不確定這是最好的/理想的解決方案。我仍然有興趣尋找其他解決方案。但是,這裏有一個方法:

存儲爲源之前,手動縮放字體點大小線高度多重顯示之前的NSAttributedString源文本屬性,然後取消規模顯示的文本。

此解決方案的問題在於,在縮放時,系統字體面板將在編輯時顯示所選文本的實際縮放顯示點大小(而不是「真實」源點大小)。這是不可取的。


下面是我實現的是:

- (void)scaleAttributedString:(NSMutableAttributedString *)str by:(CGFloat)scale { 
    if (1.0 == scale) return; 

    NSRange r = NSMakeRange(0, [str length]); 
    [str enumerateAttribute:NSFontAttributeName inRange:r options:0 usingBlock:^(NSFont *oldFont, NSRange range, BOOL *stop) { 
     NSFont *newFont = [NSFont fontWithName:[oldFont familyName] size:[oldFont pointSize] * scale]; 

     NSParagraphStyle *oldParaStyle = [str attribute:NSParagraphStyleAttributeName atIndex:range.location effectiveRange:NULL]; 
     NSMutableParagraphStyle *newParaStyle = [[oldParaStyle mutableCopy] autorelease]; 

     CGFloat oldLineHeight = [oldParaStyle lineHeightMultiple]; 
     CGFloat newLineHeight = scale * oldLineHeight; 
     [newParaStyle setLineHeightMultiple:newLineHeight]; 

     id newAttrs = @{ 
      NSParagraphStyleAttributeName: newParaStyle, 
      NSFontAttributeName: newFont, 
     }; 
     [str addAttributes:newAttrs range:range]; 
    }];  
} 

這就要求顯示之前縮放原文:

// scale text 
CGFloat scale = getCurrentScaleFactor(); 
[self scaleAttributedString:str by:scale]; 

然後反向縮放存儲爲源之前顯示的文本:

// un-scale text 
CGFloat scale = 1.0/getCurrentScaleFactor(); 
[self scaleAttributedString:str by:scale]; 
5

同時適用於iOS版和Mac OS

@implementation NSAttributedString (Scale) 

- (NSAttributedString *)attributedStringWithScale:(double)scale 
{ 
    if(scale == 1.0) 
    { 
     return self; 
    } 

    NSMutableAttributedString *copy = [self mutableCopy]; 
    [copy beginEditing]; 

    NSRange fullRange = NSMakeRange(0, copy.length); 

    [self enumerateAttribute:NSFontAttributeName inRange:fullRange options:0 usingBlock:^(UIFont *oldFont, NSRange range, BOOL *stop) { 
     double currentFontSize = oldFont.pointSize; 
     double newFontSize = currentFontSize * scale; 

     // don't trust -[UIFont fontWithSize:] 
     UIFont *scaledFont = [UIFont fontWithName:oldFont.fontName size:newFontSize]; 

     [copy removeAttribute:NSFontAttributeName range:range]; 
     [copy addAttribute:NSFontAttributeName value:scaledFont range:range]; 
    }]; 

    [self enumerateAttribute:NSParagraphStyleAttributeName inRange:fullRange options:0 usingBlock:^(NSParagraphStyle *oldParagraphStyle, NSRange range, BOOL *stop) { 

     NSMutableParagraphStyle *newParagraphStyle = [oldParagraphStyle mutableCopy]; 
     newParagraphStyle.lineSpacing *= scale; 
     newParagraphStyle.paragraphSpacing *= scale; 
     newParagraphStyle.firstLineHeadIndent *= scale; 
     newParagraphStyle.headIndent *= scale; 
     newParagraphStyle.tailIndent *= scale; 
     newParagraphStyle.minimumLineHeight *= scale; 
     newParagraphStyle.maximumLineHeight *= scale; 
     newParagraphStyle.paragraphSpacing *= scale; 
     newParagraphStyle.paragraphSpacingBefore *= scale; 

     [copy removeAttribute:NSParagraphStyleAttributeName range:range]; 
     [copy addAttribute:NSParagraphStyleAttributeName value:newParagraphStyle range:range]; 
    }]; 

    [copy endEditing]; 
    return copy; 
} 

@end