How to set up a tap gesture only for specific ranges of a UILabel in Swift 3

假如想象 提交于 2019-12-04 16:32:24
    import UIKit

    protocol SSGastureDelegate:NSObjectProtocol {
        func callBack()
    }
    class SSUnderLineLabel: UILabel {
        var tapGesture: UITapGestureRecognizer?

      //Make weak refernece for SSGastureDelegate
       weak var delegate:SSGastureDelegate?

        required init(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)!
            self.initialization()
        }
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.initialization()
        }

        func initialization(){
            let newsString: NSMutableAttributedString = NSMutableAttributedString(string: self.text!)
            let textRange = NSString(string: self.text!)
            let substringRange = textRange.range(of: "Terms and Conditions") // You can add here for own specific under line substring
            newsString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: substringRange)
           // self.attributedText = newsString.copy() as? NSAttributedString
            self.attributedText = newsString
            self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapResponse))
            self.isUserInteractionEnabled =  true
            self.addGestureRecognizer(tapGesture!)

        }

        func tapResponse(recognizer: UITapGestureRecognizer) {

            let text = (self.text)!
            let termsRange = (text as NSString).range(of: "Terms and Conditions")
            if (tapGesture?.didTapAttributedTextInLabel(label: self, inRange: termsRange))! {
                print("Tapped terms conditions")
                self.delegate?.callBack()
            }
            else {
                print("Tapped none ")
            }
        }

    }

    //MARK:UITapGestureRecognizer Extension
    //MARK:
    extension UITapGestureRecognizer {

        func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {
            // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage
            let layoutManager = NSLayoutManager()
            let textContainer = NSTextContainer(size: CGSize.zero)
            let textStorage = NSTextStorage(attributedString: label.attributedText!)

            // Configure layoutManager and textStorage
            layoutManager.addTextContainer(textContainer)
            textStorage.addLayoutManager(layoutManager)

            // Configure textContainer
            textContainer.lineFragmentPadding = 0.0
            textContainer.lineBreakMode = label.lineBreakMode
            textContainer.maximumNumberOfLines = label.numberOfLines
            let labelSize = label.bounds.size
            textContainer.size = labelSize
            // Find the tapped character location and compare it to the specified range
            let locationOfTouchInLabel = self.location(in: label)
            let textBoundingBox = layoutManager.usedRect(for: textContainer)

            let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,y:(labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
            let locationOfTouchInTextContainer = CGPoint(x:locationOfTouchInLabel.x - textContainerOffset.x,
                                                         y:locationOfTouchInLabel.y - textContainerOffset.y);
            let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
            return NSLocationInRange(indexOfCharacter, targetRange)
        }

    }*`enter code here`




**How to use it:**
Assign this class for your label and follow these steps:
Demo for use class:

ViewController.swift
//===============

class ViewController: UIViewController,SSGastureDelegate {
 @IBOutlet var underlineLbl: SSUnderLineLabel!

 override func viewDidLoad() {
      super.viewDidLoad()
     self.underlineLbl.delegate = self
 }
//Implement Delegate Method
 func callBack()
    {
//Open a specific vc for underline tap are`enter code here`a.
        let termsconditionsVC = storyboard?.instantiateViewController(withIdentifier: "TermsConditionsVC") as! TermsConditionsVC
        self.present(termsconditions, animated: true, completion: nil)

    }
}*

I see that you need your terms and privacy links to be clickable, the simple way the ios gives is AttributedString, use following code for that:

let theString = "I have agree with the terms and conditions and privacy policy"
let someAttributedString = NSMutableAttributedString(string: theString)
someAttributedString.addAttribute(NSLinkAttributeName, value: "http://www.google.com", range: NSMakeRange(22, 20))
titleLabel.attributedText = someAttributedString

TTTAttributedLabel could be your best solution: https://github.com/TTTAttributedLabel/TTTAttributedLabel

TTTAttributedLabel has following delegate

- (void)attributedLabel:(__unused TTTAttributedLabel *)label
   didSelectLinkWithURL:(NSURL *)url
{
 //do whatever you want
}

Also if you need solution from tap gesture you can find the point on gesture tap and do you calculation to check where it is tapped to perform your action by gestureRecognizer.locationInView method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!