Come rendere UILabel cliccabile su URL / telefono?


Risposte:


134

Puoi utilizzare un UITextViewe selezionare Rilevamento per collegamenti, numeri di telefono e altre cose nell'inspector.


2
Ho un'etichetta a ridimensionamento automatico che può contenere N righe di testo. Come posso rendere cliccabili i link in questa etichetta senza implementare UITextView.
bibscy

@bibscy quindi puoi usare NSAttributedText. Guarda stackoverflow.com/questions/1256887/…
Basilea

95

Usa UITextViewinvece di UILabele ha una proprietà per convertire il testo in collegamento ipertestuale.

Objective-C:

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

Swift:

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

Questo rileverà automaticamente i collegamenti.

Vedere la documentazione per i dettagli.


5
questo colora il collegamento in blu e lo sottolinea, ma sembra renderlo cliccabile, almeno su iOS 7.
Ben H

1
Codice Swift: yourTextView.editable = false; yourTextView.dataDetectorTypes = UIDataDetectorTypes.All;
Thiago Arreguy

5
la domanda riguarda UILabel, non UITextView.
swift2geek

28

https://github.com/mattt/TTTAttributedLabel

Questo è sicuramente ciò di cui hai bisogno. Puoi anche applicare attributi per l'etichetta, come la sottolineatura, e applicarvi colori diversi. Basta controllare le istruzioni per gli URL cliccabili.

Principalmente, fai qualcosa del genere:

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

12

Puoi creare un UIButton personalizzato e setText quello che vuoi e aggiungere un metodo con quello.

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
}

L'impostazione del carattere viene ora eseguita da: button.titleLabel.font = [UIFont systemFontOfSize: size];
Leon

10

Se vuoi che questo venga gestito da UILabel e non da UITextView, puoi creare una sottoclasse UILabel, come questa:

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)!)
            }
        }
    })

}}

Questa classe è stata creata riutilizzando il codice di questa risposta . Per rendere le stringhe attribuite controlla questa risposta . E qui puoi trovare come creare URL del telefono.


6

Usa questo mi è piaciuto così tanto poiché crea un collegamento con il colore blu a un testo particolare solo non sull'intero testo dell'etichetta: FRHyperLabel

Applicazione intelligente del collegamento ipertestuale sui Termini di utilizzo

Fare:

  1. Download da link qui sopra e la copia FRHyperLabel.h, FRHyperLabel.mal progetto.

  2. Drag Drop UILabelnella tua Storyboarde definire nome della classe personalizzata per FRHyperLabela identificare ispettore, come mostrato nell'immagine.

inserisci qui la descrizione dell'immagine

  1. Collega la tua UILabel dallo storyboard al tuo file viewController.h

@property (weak, nonatomic) IBOutlet FRHyperLabel *label;

  1. Ora nel tuo file viewController.m aggiungi il seguente codice.

`NSString * string = @" Caricando accetto i Termini di utilizzo "; Attributi NSDictionary * = @ {NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleHeadline]};

_label.attributedText = [[NSAttributedString alloc]initWithString:string attributes:attributes];
[_label setFont:[_label.font fontWithSize:13.0]];

[_label setLinkForSubstring:@"Terms of Use" withLinkHandler:^(FRHyperLabel *label, NSString *substring){
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.google.com"]];
}];`
  1. Ed eseguilo.

6

Usa UITextView invece di UILabel e ha una proprietà per convertire il tuo testo in collegamento ipertestuale

Codice SWIFT:

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

4
la domanda su come utilizzare in UILabel, piuttosto che TextViews. Grazie.
swift2geek

0
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

Perché non usare semplicemente NSMutableAttributedString ?

let attributedString = NSMutableAttributedString(string: "Want to learn iOS? Just visit developer.apple.com!")
        attributedString.addAttribute(.link, value: "https://developer.apple.com", range: NSRange(location: 30, length: 50))

        myView.attributedText = attributedString

Puoi trovare maggiori dettagli qui


Ho appena provato oggi a effettuare una chiamata da UILabel e il codice sopra non funziona. Ho sostituito dev.appl.com con tel: // 1234567. Può essere che questa risposta debba essere aggiornata.
Pratik Somaiya

-1

Swift 4.2, versione Xcode 9.3

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(self.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;
            }

        }
    }

    @objc 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(NSAttributedStringKey.link, 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)!)
                }
            }
        })

    }}

-3

Possibile soluzione Swift 4.0 utilizzando UIButton

     phoneButton = UIButton(frame: CGRect(x: view.frame.width * 0, y: view.frame.height * 0.1, width: view.frame.width * 1, height: view.frame.height * 0.05))
     phoneButton.setTitle("333-333-3333", for: .normal )
     phoneButton.setTitleColor(UIColor(red: 0 / 255, green: 0 / 255, blue: 238 / 255, alpha: 1.0), for: .normal)
     phoneButton.addTarget(self, action: #selector(self.callPhone), for: .touchUpInside )

     @objc func callPhone(){

         UIApplication.shared.open(URL(string:"tel://3333333333")!, options: [:] , completionHandler: nil)


    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.