代码之家  ›  专栏  ›  技术社区  ›  Damian Carrillo

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

  •  7
  • Damian Carrillo  · 技术社区  · 12 年前

    我正在创建一个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没有选项卡 停止支持,但我注意到OSX上的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 回复  |  直到 12 年前
        1
  •  10
  •   naughton    11 年前

    在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};
    
        2
  •  3
  •   RawMean    9 年前

    这是适用于我的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)
    
        3
  •  1
  •   Son of a Beach    5 年前

    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 Answer?

    早期的Swift回答是有缺陷的,因为它添加了制表位,而没有首先删除默认的制表位(12个左对齐的制表位,间距为28磅)。因此,它将一组新的制表位添加到默认的制表位集合中,而不是用新的一组制表位替换它们。使用基于该答案的代码让我非常沮丧,试图弄清楚为什么它对我不起作用,直到我回到 documentation for NSMutableParagraphStyle.tabStops 并阅读有关默认制表位的信息:

    默认值是以28点为间隔的12个左对齐选项卡的阵列。

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

        4
  •  -2
  •   Mark Fleming    11 年前

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

    因此,如果在NSAttributeString中有CTParagraphStyleRef,则会导致:

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

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