我想知道是否可以根据内容动态设置UITextView
的文字方向?
默认行为是这样的:如果您使用LTR语言开始一行该行将是LTR,但如果您使用RTL语言开始下一行该行的方向将更改为RTL。
我想要的是根据第一个设置整个段落的方向。
有可能吗?
答案 0 :(得分:9)
我自己也遇到过这个问题。通过一点点搜索,为UITextView制作了这个扩展,它可以检测第一个字母的语言,并在需要时进行RTL。 您需要在设置文本后调用该函数,因此您可能希望在UITextViewDelegate文本更改“方法中调用它。
extension UITextView {
func detectRightToLeft() {
if let text = self.text where !text.isEmpty {
let tagschemes = NSArray(objects: NSLinguisticTagSchemeLanguage)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [String], options: 0)
tagger.string = text
let language = tagger.tagAtIndex(0, scheme: NSLinguisticTagSchemeLanguage, tokenRange: nil, sentenceRange: nil)
if language?.rangeOfString("he") != nil || language?.rangeOfString("ar") != nil || language?.rangeOfString("fa") != nil {
self.text = text.stringByReplacingOccurrencesOfString("\n", withString: "\n")
self.textAlignment = .Right
self.makeTextWritingDirectionRightToLeft(nil)
}else{
self.textAlignment = .Left
self.makeTextWritingDirectionLeftToRight(nil)
}
}
}
}
当然这很混乱而且并不完美。但它对我有用。你可以得到这个想法。
斯威夫特3:
extension UITextView {
func detectRightToLeft() {
if let text = self.text, !text.isEmpty {
let tagschemes = NSArray(objects: NSLinguisticTagSchemeLanguage)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [String], options: 0)
tagger.string = text
let language = tagger.tag(at: 0, scheme: NSLinguisticTagSchemeLanguage, tokenRange: nil, sentenceRange: nil)
if language?.range(of: "he") != nil || language?.range(of: "ar") != nil || language?.range(of: "fa") != nil {
self.text = text.replacingOccurrences(of: "\n", with: "\n")
self.textAlignment = .right
self.makeTextWritingDirectionRightToLeft(nil)
}else{
self.textAlignment = .left
self.makeTextWritingDirectionLeftToRight(nil)
}
}
}
}
答案 1 :(得分:1)
基于Arash R的出色答案,这是一个Swift 4.2扩展,可以为UITextView中的每个段落分别选择文本方向。
它确定每个段落中最后一个字符的语言。这样,如果您使用RTL语言编号列表,则该段落将为RTL。
从文本更改方法中调用该函数,如果在第一次从ViewDidLoad中加载ViewController时填充了UITextView,则调用该函数。
extension UITextView {
func detectRightToLeft() {
if let text = self.text, !text.isEmpty { // Set text, make sure it is not nil
let cleanFile = text.replacingOccurrences(of: "\r", with: "\n")
var newLineIndices:Array<Int> = []
for (index, char) in cleanFile.enumerated() {
if char == "\n" {
newLineIndices.append(index) // Get location of all newline characters
}
}
newLineIndices.insert(-1, at: 0) // Place position 0 at the beginning of the array
newLineIndices.append(cleanFile.count) // Add the location after last character
let tagschemes = NSArray(objects: NSLinguisticTagScheme.language)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [NSLinguisticTagScheme], options: 0)
tagger.string = cleanFile
for i in 0..<newLineIndices.count-1 {
// Determine direction by the last character of paragraph
var taggerCounter = newLineIndices[i+1]-1
var language = tagger.tag(at: taggerCounter, scheme: NSLinguisticTagScheme.language, tokenRange: nil, sentenceRange: nil)
// Neutral characters should make the tagger look at the character before
while language == nil && taggerCounter >= 1 {
taggerCounter -= 1
language = tagger.tag(at: taggerCounter, scheme: NSLinguisticTagScheme.language, tokenRange: nil, sentenceRange: nil)
}
if String(describing: language).range(of: "he") != nil || String(describing: language).range(of: "ar") != nil || String(describing: language).range(of: "fa") != nil {
self.setBaseWritingDirection(.rightToLeft, for: self.textRange(from: self.position(from: self.beginningOfDocument, offset: newLineIndices[i]+1)!, to: self.position(from: self.beginningOfDocument, offset: newLineIndices[i+1])!)!)
print ("Right to Left Paragraph at character \(newLineIndices[i]+1)")
} else {
self.setBaseWritingDirection(.leftToRight, for: self.textRange(from: self.position(from: self.beginningOfDocument, offset: newLineIndices[i]+1)!, to: self.position(from: self.beginningOfDocument, offset: newLineIndices[i+1])!)!)
print ("Left to Right Paragraph at character \(newLineIndices[i]+1)")
}
}
}
}
}
编辑:先前版本包含一个选项,可以按段落的第一个字符进行选择。该选项导致崩溃,因此我暂时将其省略。而是,当前代码包括对中性字符的处理。另一个编辑:将taggerCounter最小值更改为1,以防止其变为负数。
答案 2 :(得分:1)
基于罗恩的答案,这是字符串的更通用扩展名
extension String {
var isRTL: Bool {
let cleanFile = self.replacingOccurrences(of: "\r", with: "\n")
var newLineIndices: Array<Int> = []
for (index, char) in cleanFile.enumerated() {
if char == "\n" {
newLineIndices.append(index)
}
}
newLineIndices.insert(-1, at: 0)
newLineIndices.append(cleanFile.count)
let tagschemes = NSArray(objects: NSLinguisticTagScheme.language)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [NSLinguisticTagScheme], options: 0)
tagger.string = cleanFile
for i in 0..<newLineIndices.count - 1 {
let language = tagger.tag(at: newLineIndices[i + 1] - 1, scheme: NSLinguisticTagScheme.language, tokenRange: nil, sentenceRange: nil)
if String(describing: language).range(of: "he") != nil || String(describing: language).range(of: "ar") != nil || String(describing: language).range(of: "fa") != nil {
return true
} else {
return false
}
}
return false
}
var isLTR: Bool {
let cleanFile = self.replacingOccurrences(of: "\r", with: "\n")
var newLineIndices: Array<Int> = []
for (index, char) in cleanFile.enumerated() {
if char == "\n" {
newLineIndices.append(index)
}
}
newLineIndices.insert(-1, at: 0)
newLineIndices.append(cleanFile.count)
let tagschemes = NSArray(objects: NSLinguisticTagScheme.language)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [NSLinguisticTagScheme], options: 0)
tagger.string = cleanFile
for i in 0..<newLineIndices.count - 1 {
let language = tagger.tag(at: newLineIndices[i + 1] - 1, scheme: NSLinguisticTagScheme.language, tokenRange: nil, sentenceRange: nil)
if String(describing: language).range(of: "he") != nil || String(describing: language).range(of: "ar") != nil || String(describing: language).range(of: "fa") != nil {
return false
} else {
return true
}
}
return false
}
}