4

チャットアプリケーションを構築していますが、パフォーマンス上の理由からUITextViewではなくUILabelを使用してチャットメッセージを表示する必要があります。私は以前TextViewを使用していましたが、スクロール時のデータ検出は非常に遅く、不安定です。UITextViewを使用しないUILabelでクリック可能なリンクを検出して作成するには

現在のところ、UILabelsのリンク/電話/アドレスなどの検出がありません。

リンクや電話番号が文字列内のどこにあるのかを確認して、それを強調表示してUILabel内でクリックできるようにするにはどうすればよいですか?

リンクの属性を追加する方法については多くの記事を読んでいますが、リンクの属性や部分文字列を知っているリンクはすべてあります。

リンクが含まれているかどうか、それらのリンクがどこにあるかを確認してから、tapGestureRecognizerをラベルに追加し、タップが発生した場所に基づいてアクションを実行したいと考えています。

私は外部ライブラリ(TTTAttributedLabel)を組み込もうとしましたが、私はswiftを使用しており、swiftのドキュメントが限られていることが判明しました。私はライブラリをインポートすることができましたが、リンクは自動的に検出されません。

答えて

2

リファレンスソース -

Create tap-able "links" in the NSAttributedString of a UILabel?

それは、迅速3.0

に変換され、これを試してみてください -

以下のようなUILabelのためのサブクラスを作成します -

スウィフト3.0

01ビューコントローラのご viewDidLoadメソッド内
class CustomLabel: UILabel { 

let layoutManager = NSLayoutManager() 
let textContainer = NSTextContainer(size: CGSize.zero) 
var textStorage = NSTextStorage() { 
    didSet { 
     textStorage.addLayoutManager(layoutManager) 
    } 
} 
var onCharacterTapped: ((_ label: UILabel, _ characterIndex: Int) -> Void)? 

let tapGesture = UITapGestureRecognizer() 

override var attributedText: NSAttributedString? { 
    didSet { 
     if let attributedText = attributedText { 
      textStorage = NSTextStorage(attributedString: attributedText) 
     } else { 
      textStorage = NSTextStorage() 
     } 
    } 
} 
override var lineBreakMode: NSLineBreakMode { 
    didSet { 
     textContainer.lineBreakMode = lineBreakMode 
    } 
} 

override var numberOfLines: Int { 
    didSet { 
     textContainer.maximumNumberOfLines = numberOfLines 
    } 
} 

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

override init(frame: CGRect) { 
    super.init(frame: frame) 
    setUp() 
} 
func setUp() { 
    isUserInteractionEnabled = true 
    layoutManager.addTextContainer(textContainer) 
    textContainer.lineFragmentPadding = 0 
    textContainer.lineBreakMode = lineBreakMode 
    textContainer.maximumNumberOfLines = numberOfLines 
    tapGesture.addTarget(self, action: #selector(CustomLabel.labelTapped(_:))) 
    addGestureRecognizer(tapGesture) 
} 

override func layoutSubviews() { 
    super.layoutSubviews() 
    textContainer.size = bounds.size 
} 

func labelTapped(_ gesture: UITapGestureRecognizer) { 
    guard gesture.state == .ended else { 
     return 
    } 
    let locationOfTouch = gesture.location(in: gesture.view) 
    let textBoundingBox = layoutManager.usedRect(for: textContainer) 
    let textContainerOffset = CGPoint(x: (bounds.width - textBoundingBox.width)/2 - textBoundingBox.minX, 
             y: (bounds.height - textBoundingBox.height)/2 - textBoundingBox.minY) 
    let locationOfTouchInTextContainer = CGPoint(x: locationOfTouch.x - textContainerOffset.x, y: locationOfTouch.y - textContainerOffset.y) 
    let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, 
                 in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) 

    onCharacterTapped?(self, indexOfCharacter) 
} 

} 

以下のようにそのクラスのインスタンスを作成します - あなたはの範囲を知っているあなたのviewDidLoad()内のリンクを追加している

override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

    let label = CustomLabel() 
    label.translatesAutoresizingMaskIntoConstraints = false 
    view.addSubview(label) 
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[view]-|", 
                     options: [], metrics: nil, views: ["view" : label])) 
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[view]-|", 
                     options: [], metrics: nil, views: ["view" : label])) 

    let attributedString = NSMutableAttributedString(string: "String with a link", attributes: nil) 
    let linkRange = NSMakeRange(14, 4); // for the word "link" in the string above 

    let linkAttributes: [String : AnyObject] = [ 
     NSForegroundColorAttributeName : UIColor.blue, NSUnderlineStyleAttributeName : NSUnderlineStyle.styleSingle.rawValue as AnyObject, 
     NSLinkAttributeName: "http://www.apple.com" as AnyObject] 
    attributedString.setAttributes(linkAttributes, range:linkRange) 

    label.attributedText = attributedString 

    label.onCharacterTapped = { label, characterIndex in 

     // DO YOUR STUFF HERE 
    } 
} 
+1

をする(14、4) 。私の場合、私はリンクの範囲を知らない。それが私が決定したいことです。 – alionthego

+0

私の知る限り、UILableを使用してこれを実現したい場合は、範囲を知っている必要があります。そうでない場合は、UITextViewを使用する必要があります。 –

+0

UITextViewはパフォーマンス上の理由からオプションではありません。 – alionthego

関連する問題