在iOS中检测UITextView中的属性文本的点击
我有一个显示NSAttributedString的UITextView。 这个字符串包含了我想要点击的单词,这样,当它们被点击时,我会被回叫,以便我可以执行一个动作。 我意识到UITextView可以检测URL上的点击并回拨我的委托,但这些不是URL。
在我看来,使用iOS7和TextKit的强大功能现在应该可以实现,但是我找不到任何示例,我不确定从哪里开始。
我明白,现在可以在字符串中创建自定义属性(尽管我还没有这样做),也许这些将有助于检测是否有一个魔术字已被挖掘? 在任何情况下,我仍然不知道如何拦截那个水龙头,并检测水龙头发生在哪个单词上。
请注意,iOS 6兼容性不是必需的。
我只是想帮助别人。 继Shmidt的回应之后,我可以完全按照我在原始问题中所提出的做法。
1)创建一个具有应用于可点击单词的自定义属性的属性字符串。 例如。
NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:@"a clickable word" attributes:@{ @"myCustomTag" : @(YES) }];
[paragraph appendAttributedString:attributedString];
2)创建一个UITextView来显示该字符串,并为其添加一个UITapGestureRecognizer。 然后处理水龙头:
- (void)textTapped:(UITapGestureRecognizer *)recognizer
{
UITextView *textView = (UITextView *)recognizer.view;
// Location of the tap in text-container coordinates
NSLayoutManager *layoutManager = textView.layoutManager;
CGPoint location = [recognizer locationInView:textView];
location.x -= textView.textContainerInset.left;
location.y -= textView.textContainerInset.top;
// Find the character that's been tapped on
NSUInteger characterIndex;
characterIndex = [layoutManager characterIndexForPoint:location
inTextContainer:textView.textContainer
fractionOfDistanceBetweenInsertionPoints:NULL];
if (characterIndex < textView.textStorage.length) {
NSRange range;
id value = [textView.attributedText attribute:@"myCustomTag" atIndex:characterIndex effectiveRange:&range];
// Handle as required...
NSLog(@"%@, %d, %d", value, range.location, range.length);
}
}
当你知道如何很容易!
更新了Swift 3
用Swift检测属性文本的点击
有时候对于初学者来说,知道如何去做事情有点困难(无论如何都是这样),所以这个例子更加完整,并且使用了Swift 3。
将UITextView
添加到您的项目中。
设置
在“属性”检查器中使用以下设置:
出口
使用名为textView
的插座将UITextView
连接到ViewController
。
码
将代码添加到您的View Controller中以检测水龙头。 请注意UIGestureRecognizerDelegate
。
import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Create an attributed string
let myString = NSMutableAttributedString(string: "Swift attributed text")
// Set an attribute on part of the string
let myRange = NSRange(location: 0, length: 5) // range of "Swift"
let myCustomAttribute = [ "MyCustomAttributeName": "some value"]
myString.addAttributes(myCustomAttribute, range: myRange)
textView.attributedText = myString
// Add tap gesture recognizer to Text View
let tap = UITapGestureRecognizer(target: self, action: #selector(myMethodToHandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap)
}
func myMethodToHandleTap(_ sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView
let layoutManager = myTextView.layoutManager
// location of tap in myTextView coordinates and taking the inset into account
var location = sender.location(in: myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndex(for: location, in: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("character index: (characterIndex)")
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substring(with: myRange)
print("character at index: (substring)")
// check if the tap location has a certain attribute
let attributeName = "MyCustomAttributeName"
let attributeValue = myTextView.attributedText.attribute(attributeName, at: characterIndex, effectiveRange: nil) as? String
if let value = attributeValue {
print("You tapped on (attributeName) and the value is: (value)")
}
}
}
}
现在,如果你点击“Swift”的“w”,你应该得到以下结果:
笔记
NSForegroundColorAttributeName
(文本颜色),有值UIColor.greenColor()
进一步研究
这个答案是基于这个问题的其他几个答案。 除此之外,另请参阅
这是一个稍微修改过的版本,基于@tarmes的答案。 如果没有下面的调整,我无法让value
变量返回任何内容,而是返回null
。 此外,我需要返回完整的属性字典才能确定最终的操作。 我会把这个在评论中,但似乎没有代表这样做。 如果我违反了协议,请提前道歉。
具体的调整是使用textView.textStorage
而不是textView.attributedText
。 作为一名仍在学习iOS的程序员,我不太确定这是为什么,但也许别人可以启发我们。
抽头处理方法中的特定修改:
NSDictionary *attributesOfTappedText = [textView.textStorage attributesAtIndex:characterIndex effectiveRange:&range];
在我的视图控制器完整的代码
- (void)viewDidLoad
{
[super viewDidLoad];
self.textView.attributedText = [self attributedTextViewString];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textTapped:)];
[self.textView addGestureRecognizer:tap];
}
- (NSAttributedString *)attributedTextViewString
{
NSMutableAttributedString *paragraph = [[NSMutableAttributedString alloc] initWithString:@"This is a string with " attributes:@{NSForegroundColorAttributeName:[UIColor blueColor]}];
NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:@"a tappable string"
attributes:@{@"tappable":@(YES),
@"networkCallRequired": @(YES),
@"loadCatPicture": @(NO)}];
NSAttributedString* anotherAttributedString = [[NSAttributedString alloc] initWithString:@" and another tappable string"
attributes:@{@"tappable":@(YES),
@"networkCallRequired": @(NO),
@"loadCatPicture": @(YES)}];
[paragraph appendAttributedString:attributedString];
[paragraph appendAttributedString:anotherAttributedString];
return [paragraph copy];
}
- (void)textTapped:(UITapGestureRecognizer *)recognizer
{
UITextView *textView = (UITextView *)recognizer.view;
// Location of the tap in text-container coordinates
NSLayoutManager *layoutManager = textView.layoutManager;
CGPoint location = [recognizer locationInView:textView];
location.x -= textView.textContainerInset.left;
location.y -= textView.textContainerInset.top;
NSLog(@"location: %@", NSStringFromCGPoint(location));
// Find the character that's been tapped on
NSUInteger characterIndex;
characterIndex = [layoutManager characterIndexForPoint:location
inTextContainer:textView.textContainer
fractionOfDistanceBetweenInsertionPoints:NULL];
if (characterIndex < textView.textStorage.length) {
NSRange range;
NSDictionary *attributes = [textView.textStorage attributesAtIndex:characterIndex effectiveRange:&range];
NSLog(@"%@, %@", attributes, NSStringFromRange(range));
//Based on the attributes, do something
///if ([attributes objectForKey:...)] //make a network call, load a cat Pic, etc
}
}
链接地址: http://www.djcxy.com/p/30673.html
上一篇: Detecting taps on attributed text in a UITextView in iOS