7

我正在创建一个 iOS 应用程序,我想显示一个属性字符串,其中包含在 UITextView 中指定的特定制表位。我还想使用 drawRect 中的核心文本将它们直接绘制到 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)];
}
4

4 回答 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};
于 2013-09-22T20:58:04.170 回答
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)
于 2015-12-10T21:21:33.523 回答
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)。因此,它将一组新的制表位添加到默认的制表位组,而不是用新的制表位组替换它们。使用基于该答案的代码让我非常沮丧,试图弄清楚为什么它对我不起作用,直到我回到NSMutableParagraphStyle.tabStops 的文档并阅读了有关默认制表位的信息:

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

这个答案纠正了这一点,并通过删除(不必要的?)“选项”以及使用循环(仅适用于所有选项卡的间距一致且所有选项卡都具有相同对齐类型的情况)变得更加简洁。

于 2020-02-10T00:46:37.340 回答
-2

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

结果,如果您在 NSAttributeString 中有 CTParagraphStyleRef ,则会导致:

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

以及 NSParagraphStyle 的其他方法,例如对齐。

于 2013-06-18T00:38:23.030 回答