如何将制表位添加到NSAttributedString并显示在UITextView中

问题描述 投票:7回答:4

我正在创建一个iOS应用,我想使用在UITextView中指定的特定制表位。我也想画使用drawRect中的Core Text直接导入UIViews中。我想要(如果可能)对于在两种情况下都将使用的相同属性字符串。

因此,在我的应用中,我创建了CFAttributedStringRef或NSAttributedString,将CTParagraphStyle属性应用于它。然后,我尝试显示UITextView中的属性字符串,出现如下所示的崩溃:

-[__NSCFType headIndent]: unrecognized selector sent to instance 0x7545080

po 0x7545080
$0 = 122966144 CTParagraphStyle:
base writing direction = -1, alignment = 4, line break mode = 0, 
   default tab interval = 0
first line head indent = 0, head indent = 0, tail indent = 0
line height multiple = 0, maximum line height = 0, minimum line height = 0
line spacing adjustment = 0, paragraph spacing = 0, 
   paragraph spacing before = 0
tabs:
(
   "CTTextTab: location = 20, alignment = 0, options = (none)\n",
   "CTTextTab: location = 40, alignment = 0, options = (none)\n",
   "CTTextTab: location = 60, alignment = 0, options = (none)\n",
   "CTTextTab: location = 80, alignment = 0, options = (none)\n",
   "CTTextTab: location = 100, alignment = 0, options = (none)\n",
   "CTTextTab: location = 120, alignment = 0, options = (none)\n"
)

我了解发生了什么,但是我想知道是否还有其他方法做我想做的事。 iOS上的NSMutableParagraphStyle没有标签停止支持,但我注意到OS X上的NSMutableParagraphStyle确实有此功能能力。这使我认为iOS NSMutableParagraphStyle可能有一天支持这一点。

同时,是否可以将制表位添加到CFAttributedStringRef或NSAttributedString并仍然显示UITextView吗?

有问题的来源是:

- (void)viewWillAppear:(BOOL)animated
{
   CFDictionaryRef attrs = (__bridge CFDictionaryRef) @{};
   CFAttributedStringRef a = CFAttributedStringCreate(
       kCFAllocatorDefault, CFSTR("a\tb\tc\td"), attrs);

   CFMutableAttributedStringRef attrStr;
   attrStr = CFAttributedStringCreateMutableCopy(
       kCFAllocatorDefault, CFAttributedStringGetLength(a), a);

   CFArrayRef tabStops = (__bridge CFArrayRef) @[
       (__bridge id) CTTextTabCreate(0, 20, NULL),
       (__bridge id) CTTextTabCreate(0, 40, NULL),
       (__bridge id) CTTextTabCreate(0, 60, NULL),
       (__bridge id) CTTextTabCreate(0, 80, NULL),
       (__bridge id) CTTextTabCreate(0, 100, NULL),
       (__bridge id) CTTextTabCreate(0, 120, NULL)];

   const CTParagraphStyleSetting paraSettings[] = {
       {kCTParagraphStyleSpecifierTabStops, sizeof(CFArrayRef), &tabStops},
   };

   CTParagraphStyleRef paraStyle = CTParagraphStyleCreate(
       paraSettings, 
       sizeof(paraSettings) / sizeof(CTParagraphStyleSetting));

   CFRange range = CFRangeMake(0, CFAttributedStringGetLength(attrStr));
   CFAttributedStringSetAttribute(
       attrStr, range, kCTParagraphStyleAttributeName, paraStyle);

   CFRelease(paraStyle);
   CFIndex i, count = CFArrayGetCount(tabStops);
   for (i = 0; i < count; i++) {
       CFRelease(CFArrayGetValueAtIndex(tabStops, i));
   }

   [[self textView] setAttributedText:
       (__bridge NSAttributedString *)(attrStr)];
}
iphone core-text nsattributedstring
4个回答
10
投票

在iOS 7中,您可以这样操作:

UIFont *font = [UIFont systemFontOfSize:18.0];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
NSInteger cnt;
CGFloat tabInterval = 72.0;
paragraphStyle.defaultTabInterval = tabInterval;
NSMutableArray *tabs = [NSMutableArray array];
for (cnt = 1; cnt < 13; cnt++) {    // Add 12 tab stops, at desired intervals...
    [tabs addObject:[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:tabInterval * cnt options:nil]];
}
paragraphStyle.tabStops = tabs;
NSDictionary *attributes = @{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle};

3
投票

这是对我有用的Swift版本:

    let tablInterval: CGFloat = 85.0
    let paragraphStyle = NSMutableParagraphStyle()
    let terms = NSTextTab.columnTerminatorsForLocale(NSLocale.currentLocale())
    let tabStop0 = NSTextTab(textAlignment: .Right, location: 0, options: [NSTabColumnTerminatorsAttributeName:terms])
    let tabStop1 = NSTextTab(textAlignment: .Right, location: tablInterval, options: [NSTabColumnTerminatorsAttributeName:terms])
    let tabStop2 = NSTextTab(textAlignment: .Right, location: tablInterval*2, options: [NSTabColumnTerminatorsAttributeName:terms])
    let tabStop3 = NSTextTab(textAlignment: .Right, location: tablInterval*3, options: [NSTabColumnTerminatorsAttributeName:terms])
    paragraphStyle.addTabStop(tabStop0)
    paragraphStyle.addTabStop(tabStop1)
    paragraphStyle.addTabStop(tabStop2)
    paragraphStyle.addTabStop(tabStop3)

    let attributedString = NSMutableAttributedString(string:text)
    attributedString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:rangeAll)

0
投票

Swift的改进/更正答案:

let tablInterval: CGFloat = 20.0
var tabsArray = [NSTextTab]()
for i in 1...6 {
    tabsArray.append(NSTextTab(textAlignment: .Left, location: i*tabInterval, options: [:]))
}
let paraStyle = NSMutableParagraphStyle()
paraStyle.tabStops = tabsArray
textView.attributedString = NSAttributedString(string: text, attributes: [NSAttributedString.Key.ParagraphStyle: paraStyle])

为什么要这个额外的Swift答案?

较早的Swift答案是有缺陷的,因为它在不先删除默认制表位的情况下添加了制表位(12个左对齐的制表位,间距为28 pt)。因此,它向默认的一组制表位添加了一组新的制表位,而不是将其替换为新的制表位。使用基于该答案的代码使我非常沮丧,试图弄清楚为什么它对我不起作用,直到我回到documentation for NSMutableParagraphStyle.tabStops并了解默认的制表位:

默认值是一个28点间隔的12个左对齐制表符的数组。

此答案可以解决此问题,并且通过删除(不必要的?)“选项”以及使用循环(使其更简洁)(仅在所有制表符间距一致且所有对齐类型均相同的情况下才适用) )。


-2
投票

ios 6.1添加了NSParagraphStyle,但CTParagraphStyleRef和NSParagraphStyle似乎不是免费的桥接。

因此,如果NSAttributeString中包含CTParagraphStyleRef,则会导致:

[__ NSCFType headIndent]:无法识别的选择器已发送到实例xxxx

和其他NSParagraphStyle方法,例如对齐。

© www.soinside.com 2019 - 2024. All rights reserved.