许多应用程序都有文本,文本中是圆角矩形的web超链接,当我点击它们时,UIWebView就会打开。让我困惑的是,他们经常有自定义链接,例如,如果单词以#开头,它也是可点击的,应用程序通过打开另一个视图来响应。我该怎么做呢?是否可以用UILabel或者我需要UITextView或者其他什么?
当前回答
我遵循这个版本,
斯威夫特4:
import Foundation
class AELinkedClickableUILabel: UILabel {
typealias YourCompletion = () -> Void
var linkedRange: NSRange!
var completion: YourCompletion?
@objc func linkClicked(sender: UITapGestureRecognizer){
if let completionBlock = completion {
let textView = UITextView(frame: self.frame)
textView.text = self.text
textView.attributedText = self.attributedText
let index = textView.layoutManager.characterIndex(for: sender.location(in: self),
in: textView.textContainer,
fractionOfDistanceBetweenInsertionPoints: nil)
if linkedRange.lowerBound <= index && linkedRange.upperBound >= index {
completionBlock()
}
}
}
/**
* This method will be used to set an attributed text specifying the linked text with a
* handler when the link is clicked
*/
public func setLinkedTextWithHandler(text:String, link: String, handler: @escaping ()->()) -> Bool {
let attributextText = NSMutableAttributedString(string: text)
let foundRange = attributextText.mutableString.range(of: link)
if foundRange.location != NSNotFound {
self.linkedRange = foundRange
self.completion = handler
attributextText.addAttribute(NSAttributedStringKey.link, value: text, range: foundRange)
self.isUserInteractionEnabled = true
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(linkClicked(sender:))))
return true
}
return false
}
}
电话的例子:
button.setLinkedTextWithHandler(text: "This website (stackoverflow.com) is awesome", link: "stackoverflow.com")
{
// show popup or open to link
}
其他回答
NSString *string = name;
NSError *error = NULL;
NSDataDetector *detector =
[NSDataDetector dataDetectorWithTypes:(NSTextCheckingTypes)NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber
error:&error];
NSArray *matches = [detector matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches)
{
if (([match resultType] == NSTextCheckingTypePhoneNumber))
{
NSString *phoneNumber = [match phoneNumber];
NSLog(@" Phone Number is :%@",phoneNumber);
label.enabledTextCheckingTypes = NSTextCheckingTypePhoneNumber;
}
if(([match resultType] == NSTextCheckingTypeLink))
{
NSURL *email = [match URL];
NSLog(@"Email is :%@",email);
label.enabledTextCheckingTypes = NSTextCheckingTypeLink;
}
if (([match resultType] == NSTextCheckingTypeLink))
{
NSURL *url = [match URL];
NSLog(@"URL is :%@",url);
label.enabledTextCheckingTypes = NSTextCheckingTypeLink;
}
}
label.text =name;
}
UIButtonTypeCustom是一个可点击的标签,如果你没有为它设置任何图像。
从iOS 15开始,SwiftUI内置支持Markdown标记语言,因此Markdown中的文本:
Text("You can [click this link](https://www.example.com) to visit the website.")
或者作为一个使用SwiftUI的最简单的例子,你可以这样做:
HStack() {
Text("Open the")
.foregroundColor(.black)
Link(destination: URL(string: "https://www.example.com/TOS.html")!) {
Text("link")
.foregroundColor(.blue)
.underline()
}
Text("in browser")
.foregroundColor(.black)
}
在Swift 3中工作,将整个代码粘贴在这里
//****Make sure the textview 'Selectable' = checked, and 'Editable = Unchecked'
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet var theNewTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
//****textview = Selectable = checked, and Editable = Unchecked
theNewTextView.delegate = self
let theString = NSMutableAttributedString(string: "Agree to Terms")
let theRange = theString.mutableString.range(of: "Terms")
theString.addAttribute(NSLinkAttributeName, value: "ContactUs://", range: theRange)
let theAttribute = [NSForegroundColorAttributeName: UIColor.blue, NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue] as [String : Any]
theNewTextView.linkTextAttributes = theAttribute
theNewTextView.attributedText = theString
theString.setAttributes(theAttribute, range: theRange)
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if (URL.scheme?.hasPrefix("ContactUs://"))! {
return false //interaction not allowed
}
//*** Set storyboard id same as VC name
self.navigationController!.pushViewController((self.storyboard?.instantiateViewController(withIdentifier: "TheLastViewController"))! as UIViewController, animated: true)
return true
}
}
我们使用来自zekel的UITapGestureRecognizer类别的方便解决方案。 它使用了NSTextContainer,就像这个问题的许多答案一样。
但是,这将返回错误的字符索引。显然是因为NSTextContainer缺少关于字体样式的信息,正如这些其他帖子所指出的:
https://stackoverflow.com/a/34238382/2439941 https://stackoverflow.com/a/47358270/2439941
后改变:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:label.attributedText];
To:
// Apply the font of the label to the attributed text:
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:label.attributedText];
NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
paragraphStyle.alignment = self.label.textAlignment;
[attributedText addAttributes:@{NSFontAttributeName: label.font, NSParagraphStyleAttributeName: paragraphStyle}
range:NSMakeRange(0, label.attributedText.string.length)];
// Init with attributed text from label:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
结果明显更好,点击区域现在正确地从目标字符串的第一个字符开始。但最后一个字符仍然返回NO。我们期望这与我们的目标字符串具有将字体权重设置为UIFontWeightSemibold的属性有关。而上面的代码改进应用标签。整个字符串上的字体,它有一个规则的权重。
为了解决这个问题,我们进一步改进了上面的代码片段,通过遍历所有属性范围,以支持文本中的多种字体样式:
// According to https://stackoverflow.com/a/47358270/2439941 it's required to apply the paragraph style and font of the UILabel.
// However, the attributed string might contain font formatting as well, e.g. to emphasize a word in a different font style.
// Therefor copy all attributes:
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:label.attributedText];
[label.attributedText enumerateAttributesInRange:NSMakeRange(0, label.attributedText.length)
options:0
usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
// Add each attribute:
[attributedText addAttributes:attrs
range:range];
// In case the attributes of this range do NOT contain a font specifier, apply the font from the UILabel:
if (![attrs objectForKey:NSFontAttributeName]) {
[attributedText addAttributes:@{ NSFontAttributeName : label.font }
range:range];
}
}];
// Init the storage with the font attributed text:
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
现在,该方法为半粗体字符串范围内的每个字符返回YES,这是预期的结果。
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- Swift:声明一个空字典
- 我如何用javascript编程点击链接?
- 在成功提交我的应用程序后,“太多符号文件”
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- CFNetwork SSLHandshake iOS 9失败
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0
- 缺少推荐的图标文件-该包不包含iPhone / iPod Touch的应用程序图标,像素为“120x120”,png格式
- 以编程方式创建segue