问题
I have an attributed string
set to UILabel
with multiple underlines
, colors
like below image
and I know How to setup a tap gesture for whole label (with enabling user interaction
) and below is my code for what I have done including setting up underline
and setting up font colors
for multiple ranges
.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var mylabel: UILabel!
var theString = "I have agree with the terms and conditions and privacy policy"
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = theString
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.printme))
mylabel.addGestureRecognizer(tap)
setUnderline(theText: theString)
// Do any additional setup after loading the view, typically from a nib.
}
func printme() {
print("print this")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setUnderline(theText : String) {
//set up underline
let textRange1 = NSMakeRange(22, 19)
let textRange2 = NSMakeRange(47, (theText.characters.count-47))
let attributedText = NSMutableAttributedString(string : theText)
attributedText.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: textRange1)
attributedText.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: textRange2)
//setup colors
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSRange(location: 22,length: 20))
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSRange(location: 47,length: (theText.characters.count-47)))
mylabel.attributedText = attributedText
}
- The
tap
gesture work forwhole label
. what I want is when user tap on "terms and conditions" fire a different function and and when user tap on "privacy policy" fire another different function. how can I do that.
Note : I want to fire two different functions one for "terms and conditions" tap, and other for "privacy policy" tap, and do not want to just open links
回答1:
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)
}
}*
回答2:
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
来源:https://stackoverflow.com/questions/40512606/how-to-set-up-a-tap-gesture-only-for-specific-ranges-of-a-uilabel-in-swift-3