7

Я читаю строки из Localizable.strings, которые содержат что-то вроде того, что в основном есть у вас в файле strings.xml приложения для AndroidСоздайте атрибутную строку из обычного (Android форматированного) текста в swift для iOS

"testShort" = "A <b>short</b>\ntest with another<b>bold text</b>"; 

Жирные и строковые каналы - это только два атрибута форматирования, которые у меня есть в моих текстах. Я пытаюсь разработать метод, как это в течение нескольких дней теперь без успеха:

func ConvertText(inputText: String) -> NSAttributedString { 
    // here comes the conversion to a representation with Helvetica 14pt and Helvetica-Bold 14pt including line feeds. 
} 

Моя конечная цель, чтобы отобразить текст в attributedText UITextView давал в.

Быть новым для Swift и iOS, не зная Objective-C Мне было очень сложно делать манипуляции с String, так как они совершенно разные и сложные, и все примеры находятся в Objective-C. Что еще более усложняет, так это то, что большинство методов API недоступны или отличаются в Swift, чем в Objective-C ...

Вот что я пробовал до сих пор для тела метода с помощью множества других сообщений здесь :

var test = inputText.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)! 
attrStr = NSAttributedString(
     data: test, 
     options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], 
     documentAttributes: nil, 
     error: nil)! 
return attrStr 

Основные проблемы здесь, что \n не преобразованный и шрифт очень маленький и по-другому.

Далее я попытался вручную выделить часть текста вручную. Это, кажется, работает так:

var newText = NSMutableAttributedString(string: inputText) 
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: NSRange(location:2,length:4)) 

Теперь я пытался искать атрибуты в тексте, удаляя их и использовать AddAttribute вроде как тот

// Start of bold text 
var range = newText.rangeOfString("<b>")! 
// End of bold text 
var range2 = newText.rangeOfString("</b>")! 

// replacing attributes 
newText = newText.stringByReplacingCharactersInRange(range, withString: "") 
newText = newText.stringByReplacingCharactersInRange(range2, withString: "") 

// creating a range for bold => error "'String.Index' is not convertible to 'int'" 
// how to do such a thing 
var boldRange = NSMakeRange(range.startIndex, range2.endIndex -3) 

// setting bold 
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: boldRange) 

Это целый ряд вещь моя главная проблема на данный момент, поскольку он совершенно отличается от простой позиции в строке.

Этот вопрос является отличным примером отсутствия (или хорошо скрытой) документация:

addAttribute хочет NSRange, то rangeOfString, кажется, поставить общий диапазон в соответствии с сообщением об ошибке я получаю - но есть нет информации об этом. Кнопка «Поиск документации» в Xcode на rangeOfString() приводит к NSString. Поиск там rangeOfString() говорит, что он возвращает NSRange. Нажатие на это приводит к информации о псевдониме типа для _NSRange, который, в свою очередь, имеет два свойства NSUInteger с именем location и length. Где свойство startIndex и endIndex, которое я вижу в XCode? Очень смущающе ...

Было бы здорово, если бы вы могли дать мне несколько фрагментов или подсказок, где я ошибаюсь здесь или даже тело метода, поскольку я все еще надеюсь, что это не так сложно, если вы хорошо знаете iOS и Swift. Я нацелен на поддержку iOS 7.1, но, если его проще с iOS 8, это тоже хорошо.

+0

Смелый эффект диапазона: 'NSMakeRange (range.location, range2.location-range.location)'. Отсутствует, может быть, факт, что вы «удалили» в то же время «» и «», что означает, что у вас могут быть различия 3 или 3 + 4. – Larme

+0

Ларн, я пробовал это. Xcode выдает мне ошибку _'Range 'не имеет члена с именем' location'_, который объясняется объяснением Martin R, размещенным ниже – Soko

ответ

7

Что касается первого метода с NSAttributedString:

  • \n символами в HTML является просто обычным белым пространством. Чтобы получить перерыв линии, вам нужно будет заменить на <br />.
  • Атрибутами шрифта можно управлять с помощью HTML <span>, см. Parsing HTML into NSAttributedText - how to set font?.

Это дает (в настоящее время обновляется для Swift 2):

func convertText(inputText: String) -> NSAttributedString { 

    var html = inputText 

    // Replace newline character by HTML line break 
    while let range = html.rangeOfString("\n") { 
     html.replaceRange(range, with: "<br />") 
    } 

    // Embed in a <span> for font attributes: 
    html = "<span style=\"font-family: Helvetica; font-size:14pt;\">" + html + "</span>" 

    let data = html.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)! 
    let attrStr = try? NSAttributedString(
     data: data, 
     options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], 
     documentAttributes: nil) 
    return attrStr! 
} 

Что касается вашего второго метода:

Есть два различных rangeOfString() методы, один для (Swift) String и один за (основа) NSString. Метод String возвращает Range<String.Index> , а метод NSString возвращает NSRange.

Преобразование между этими двумя возможно, но сложное. Причина в том, что в a String каждый «расширенный кластер графем» считается одним символом, тогда как в NSString подсчитывается каждый блок UTF-16. Расширенным кластером графем может быть один или несколько единиц UTF-16 («« это два блока UTF-16 »,« четыре »).

Метод addAttribute() принимает только NSRange. Самый простой способ решить - это преобразовать строку Swift в NSString и работать только с NSRange . Тогда ваш метод может выглядеть так:

func convertText(inputText: String) -> NSAttributedString { 

    let attrString = NSMutableAttributedString(string: inputText) 
    let boldFont = UIFont(name: "Helvetica-Bold", size: 14.0)! 

    var r1 = (attrString.string as NSString).rangeOfString("<b>") 
    while r1.location != NSNotFound { 
     let r2 = (attrString.string as NSString).rangeOfString("</b>") 
     if r2.location != NSNotFound && r2.location > r1.location { 
      let r3 = NSMakeRange(r1.location + r1.length, r2.location - r1.location - r1.length) 
      attrString.addAttribute(NSFontAttributeName, value: boldFont, range: r3) 
      attrString.replaceCharactersInRange(r2, withString: "") 
      attrString.replaceCharactersInRange(r1, withString: "") 
     } else { 
      break 
     } 
     r1 = (attrString.string as NSString).rangeOfString("<b>") 
    } 

    return attrString 
} 
+0

Большое спасибо Мартину. Ваши методы отлично работают, даже для iOS 7.1. Какой из них вы предпочитаете (какой из них быстрее)? Ох, и нет ли на самом деле никакой документации о методе rangeOfString() '' или его возвращаемом типе 'Range ' или это только хорошо скрыто? Я надеюсь, что есть веская причина, чтобы Strings так усложнились в Swift ... – Soko

+1

@Soko: Я не использовал ни один из них, поэтому я не могу сказать ничего о скорости. Я, вероятно, предпочел бы # 1, потому что он более общий и может обрабатывать другие атрибуты HTML. # 2 на самом деле довольно подвержен ошибкам (что, если тег написан как '' с пробелом?). 'Range ' легко, как только вы почувствуете это :) У меня нет хорошей ссылки, но здесь уже много вопросов и ответов. –