web-dev-qa-db-fra.com

Comment faire UILabel cliquable par téléphone/URL?

Je souhaite créer une étiquette cliquable sur mon application menant à une page Web Safari. Je souhaite également que l'utilisateur ne puisse téléphoner aux numéros qu'en cliquant dessus. 

Merci pour vos conseils

97
Rob

Vous pouvez utiliser une variable UITextView et sélectionner Détection des liens, des numéros de téléphone et d'autres éléments dans l'inspecteur.

121
Basel

Utilisez UITextView au lieu de UILabel et il a une propriété pour convertir votre texte en lien hypertexte.

Objectif c:

yourTextView.editable = NO;
yourTextView.dataDetectorTypes = UIDataDetectorTypeAll;

Rapide:

yourTextView.editable = false; 
yourTextView.dataDetectorTypes = UIDataDetectorTypes.All;

Cela détectera les liens automatiquement.

Voir la documentation pour plus de détails.

92

https://github.com/mattt/TTTAttributedLabel

C'est vraiment ce dont vous avez besoin. Vous pouvez également appliquer des attributs à votre étiquette, tels que le soulignement, et lui appliquer différentes couleurs. Il suffit de vérifier les instructions pour les URL cliquables.

Principalement, vous faites quelque chose comme ceci:

NSRange range = [label.text rangeOfString:@"me"];
[label addLinkToURL:[NSURL URLWithString:@"http://github.com/mattt/"] withRange:range]; // Embedding a custom link in a substring
27
Ramy Kfoury

Vous pouvez personnaliser UIButton et setText comme bon vous semble et y ajouter une méthode.

    UIButton *sampleButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [sampleButton setFrame:CGRectMake(kLeftMargin, 10, self.view.bounds.size.width - kLeftMargin - kRightMargin, 52)];
    [sampleButton setTitle:@"URL Text" forState:UIControlStateNormal];
    [sampleButton setFont:[UIFont boldSystemFontOfSize:20]];

    [sampleButton addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:sampleButton];

-(void)buttonPressed:(id)sender{
 // open url

}
12
Rohit Dhawan

Utilisez UITextView au lieu de UILabel et il a une propriété pour convertir votre texte en hyperlien

Code rapide:

yourTextView.editable = false
yourTextView.dataDetectorTypes = UIDataDetectorTypes.All
//or
yourTextView.dataDetectorTypes = UIDataDetectorTypes.PhoneNumber
//or
yourTextView.dataDetectorTypes = UIDataDetectorTypes.Link
7
Thiago Arreguy

Si vous voulez que cela soit géré par UILabel et non par UITextView, vous pouvez créer une sous-classe UILabel, comme celle-ci:

class LinkedLabel: UILabel {

fileprivate let layoutManager = NSLayoutManager()
fileprivate let textContainer = NSTextContainer(size: CGSize.zero)
fileprivate var textStorage: NSTextStorage?


override init(frame aRect:CGRect){
    super.init(frame: aRect)
    self.initialize()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.initialize()
}

func initialize(){

    let tap = UITapGestureRecognizer(target: self, action: #selector(LinkedLabel.handleTapOnLabel))
    self.isUserInteractionEnabled = true
    self.addGestureRecognizer(tap)
}

override var attributedText: NSAttributedString?{
    didSet{
        if let _attributedText = attributedText{
            self.textStorage = NSTextStorage(attributedString: _attributedText)

            self.layoutManager.addTextContainer(self.textContainer)
            self.textStorage?.addLayoutManager(self.layoutManager)

            self.textContainer.lineFragmentPadding = 0.0;
            self.textContainer.lineBreakMode = self.lineBreakMode;
            self.textContainer.maximumNumberOfLines = self.numberOfLines;
        }

    }
}

func handleTapOnLabel(tapGesture:UITapGestureRecognizer){

    let locationOfTouchInLabel = tapGesture.location(in: tapGesture.view)
    let labelSize = tapGesture.view?.bounds.size
    let textBoundingBox = self.layoutManager.usedRect(for: self.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 = self.layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: self.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)


    self.attributedText?.enumerateAttribute(NSLinkAttributeName, in: NSMakeRange(0, (self.attributedText?.length)!), options: NSAttributedString.EnumerationOptions(rawValue: UInt(0)), using:{
        (attrs: Any?, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in

        if NSLocationInRange(indexOfCharacter, range){
            if let _attrs = attrs{

                UIApplication.shared.openURL(URL(string: _attrs as! String)!)
            }
        }
    })

}}

Cette classe a été faite en réutilisant le code de cette answer . Afin de faire des chaînes attribuées, consultez cette réponse . Et ici vous pouvez trouver comment créer des URL de téléphone.

7
Bojan Bozovic
extension UITapGestureRecognizer {

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool {

        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
        textContainer.size = label.bounds.size

        // main code
        let locationOfTouchInLabel = self.location(in: label)

        let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInLabel, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        let indexOfCharacterRange = NSRange(location: indexOfCharacter, length: 1)
        let indexOfCharacterRect = layoutManager.boundingRect(forGlyphRange: indexOfCharacterRange, in: textContainer)
        let deltaOffsetCharacter = indexOfCharacterRect.Origin.x + indexOfCharacterRect.size.width

        if locationOfTouchInLabel.x > deltaOffsetCharacter {
            return false
        } else {
            return NSLocationInRange(indexOfCharacter, targetRange)
        }
    }
}
0
Harman