使用TextKit突出显示单词,选择错误的重复单词

时间:2017-01-11 15:18:56

标签: swift nsattributedstring nsrange textkit

我实际上正在开发一个古兰经应用程序,其中我使用TextKit突出显示经文并改变它们的颜色。一切都很好,但我有一些问题,出现多次。首先,我的代码是:

    import UIKit

class ViewController: UIViewController {

    let attributedBackgroundColor = [ NSBackgroundColorAttributeName: UIColor.lightGray ]
    var myVerses = ["بِسْمِ اللَّهِ الرَّحْمَنِ الرَّحِيمِ","الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ","الرَّحْمَنِ الرَّحِيمِ","مَالِكِ يَوْمِ الدِّينِ","إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ","اهدِنَا الصِّرَاطَ الْمُسْتَقِيمَ","صِرَاطَ الَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ الْمَغْضُوبِ عَلَيْهِمْ وَلاَ الضَّالِّينَ"]

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

       let string = NSMutableAttributedString(string: "Vide initialement")
        string.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: CGFloat(25.0)), range: NSRange(location: 0, length: string.length))
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length))

        textView.attributedText = string
        let singleTap = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapRecognized))
        singleTap.numberOfTapsRequired = 1
        textView.addGestureRecognizer(singleTap)
        textView.isEditable = false
        textView.isSelectable = false

        var str = ""

// Ajouter numérotation aux verses - Add numerotation to verses.
        for i in 0..<myVerses.count {
            if i > 0 {
                str += "("+"\(i)"+")"
            }
            str += String(myVerses[i])
        }
        print(str)
        textView.text = str + "("+"\(myVerses.count)"+")"
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }


   // Sélection des verses - Select Verses
    func tapRecognized(_ recognizer: UITapGestureRecognizer) {
        if recognizer.state == .recognized {
            let point = recognizer.location(in: recognizer.view)
            let detectedText = self.getWordAtPosition(pos: point, in: textView)
            if (detectedText != "") {
                print("detectedText  == \(detectedText)")
                let string = NSMutableAttributedString(string: self.textView.text)
                let verses = self.textView.text.components(separatedBy: ")")



                if let detectedRange = textView.text.range(of: detectedText) {
                    let startPosOfSubstring = textView.text.distance(from: textView.text.startIndex, to: detectedRange.lowerBound)
                    let detectedLength = detectedText.characters.count
               let rangeOfSub = (startPosOfSubstring,detectedLength)
               print("-- rangeofSub == " ,rangeOfSub)
                    let rangeOfSubstring = NSRange(location: startPosOfSubstring, length: detectedLength)


                    for verse: String in verses {
                        if let detectedVerse = textView.text.range(of: verse) {
                            let startPosOfVerse = textView.text.distance(from: textView.text.startIndex, to: detectedVerse.lowerBound)
                            let detectedLengthOfVerse = verse.characters.count

                            let tupleVerse = (startPosOfVerse,detectedLengthOfVerse)
                            print("++ rangeofVerse == " ,tupleVerse)
                            let rangeOfVerse = NSRange(location: startPosOfVerse, length: detectedLengthOfVerse)
                            print(verse)


                            let range = (self.textView.text as NSString).range(of: verse)
                            let contained = NSLocationInRange(rangeOfSubstring.location, rangeOfVerse)
                            if (contained) {
                                print ("************************************")
                            print("contained is :" ,contained)
                                print ("************************************")

                                string.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: range)
                                string.addAttribute(NSBackgroundColorAttributeName, value: UIColor.darkGray, range: range)
                                string.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: CGFloat(25.0)), range: NSRange(location: 0, length: string.length))
                                let paragraphStyle = NSMutableParagraphStyle()
                                paragraphStyle.alignment = .center
                                string.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: string.length))

                            }
                            print ("--------------------------------------------")

                        }

                    }
                    self.textView.attributedText = string
                } else {
                    print("detectedText is empty")
                }
            }
        }
    }



    func getWordAtPosition( pos: CGPoint, in textview: UITextView) -> String {
        //Eleminer le balancement du scroll - eliminate scroll offset
     //   var pos = pos
    //    pos.y += tv.contentOffset.y
        //Position du text tapé au point - get location in text from textposition at point
        let tapPos = textview.closestPosition(to: pos)
        //Avoir le mot tapé dans la position du point - fetch the word at this position (or nil, if not available)
        if let wr = textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .word, inDirection: UITextLayoutDirection.right.rawValue) {
            print(pos)
            return textview.text(in: wr)!
        }else{
            return ""
        }

    }
}

当我在模拟器上运行我的应用程序时,我选择了一个经文并且它很棒。

正常使用:

Normal Use

问题在于出现不止一次的单词。例如,对于发现两次的单词“الرحمن”,无论我选择第一个还是第二个,突出显示的经文始终是第一个。

Problem

我做错了什么? 提前致谢。

1 个答案:

答案 0 :(得分:0)

根据我的理解,当用户选择该节目中的特定单词时,您希望突出显示整个经文。

您的逻辑中的问题是您确定用户选择的单词,但该单词不一定是唯一的,因此当您搜索此单词(使用textView.text.range(of: detectedText))时,您将获得第一个结果,可能是也可能不是用户实际选择的那个。

如果令牌化程序正确理解您的文本,一种可能的解决方案是在确定用户的选择时使用不同的TextGranularity。而不是:

textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .word, inDirection: UITextLayoutDirection.right.rawValue)
你可以尝试:

textview.tokenizer.rangeEnclosingPosition(tapPos!, with: .sentence, inDirection: UITextLayoutDirection.right.rawValue)