UITextView link tap recognition is delayed
Is the UITextView
selectable?. Try with:
self.textView.selectable = YES;
Edit:
I'm starting to think that maybe a long-press is the only way to fire it contrary to what apple says. Check this link, maybe it will help.
UITextView open link on tap
The example below only works on iOS 8+
Tap recognizer:
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("tappedTextView:"))
myTextView.addGestureRecognizer(tapRecognizer)
myTextView.selectable = true
Callback:
func tappedTextView(tapGesture: UIGestureRecognizer) {
let textView = tapGesture.view as! UITextView
let tapLocation = tapGesture.locationInView(textView)
let textPosition = textView.closestPositionToPoint(tapLocation)
let attr: NSDictionary = textView.textStylingAtPosition(textPosition, inDirection: UITextStorageDirection.Forward)
if let url: NSURL = attr[NSLinkAttributeName] as? NSURL {
UIApplication.sharedApplication().openURL(url)
}
}
Swift 3 and no force unwraps:
func tappedTextView(tapGesture: UIGestureRecognizer) {
guard let textView = tapGesture.view as? UITextView else { return }
guard let position = textView.closestPosition(to: tapGesture.location(in: textView)) else { return }
if let url = textView.textStyling(at: position, in: .forward)?[NSLinkAttributeName] as? URL {
UIApplication.shared.open(url)
}
}
Detecting tap on a UITextView only detects cancellations
I did as Ralfonso said without success, but it helped me realize I had a gesture recognizer conflict. Turns out I didn't have to override all 4 methods of the UITextView, I just override the touchesBegan.
What I was doing in the viewDidLoad was add a gesture recognizer to dismiss the keyboard :
var tapOutTextField: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
self.view.addGestureRecognizer(tapOutTextField)
What didn't make sense and sent me in a wrong direction was that touchesBegan was actually called after a delay (so was touchCancelled), and I could not get the same behaviour as a UIButton. All that because of this gesture recognizer conflict.
is there any chance to identify if empty space has been tapped in UITextView?
Ok, so I got it working like expected. The solution is to check if the tapped position is the end of the document:
if let position = textView.closestPosition(to: location) {
if position == textView.endOfDocument {
return true
}
}
The final code looks like that:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let textView = textView, textView.text.count > 0 {
var location = touch.location(in: textView)
location.x -= textView.textContainerInset.left
location.y -= textView.textContainerInset.top
if let position = textView.closestPosition(to: location) {
if position == textView.endOfDocument {
return true
}
}
let characterIndex = textView.layoutManager.characterIndex(for: location, in: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
if (textView.attributedText?.attribute(.link, at: characterIndex, effectiveRange: nil) as? URL) != nil {
return false
}
}
return true
}
How can I click a link in the UITextView and get the position of the 'tap' at the same time
override hitTest:withEvent
method
signature
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
Above method is supplied with CGPoint which is the location of touch.Create a CGPoint class property and store the touch-location in it.
@property (nonatomic,assign) CGPoint previousTouch;
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
self.previousTouch = point;
return [super hitTest:point withEvent:event];
}
UITextView appearance delayed
Replace [self fetchData];
with
[self performSelectorInBackground:@selector(fetchData) withObject:nil];
Then inside your fetchData
method, after your fetch is done, add
[self performSelectorOnMainThread:@selector(fetchDataFinished) withObject:nil waitUntilDone:NO];
where the new method fetchDataFinished
is defined as
-(void) fetchDataFinished{
[self.tableView reloadData];
[self.textView removeFromSuperview];
}
Note that you have to make textView
a property so it is accessible in this method.
I have not tried out the above for your particular case, but I have used similar constructs successfully in many similar situations.
Related Topics
How to Disable Calayer Implicit Animations
How to Get Screen Size Using Code on iOS
Add Nsurlconnection Loading Process on Uiprogressview
How to Find Indexpath for Tapped Button in Tableview Using Seque
Alternatives to Weak Linking in iPhone Sdk
iOS App Crashes, Xcode Says 'Lost Connection to X's Iphone' When Debugging
Firebase for iOS, Googleservice-Info.Plist Property "Is_Analytics_Enabled" Set to "No"
Facebook Login Issue - Canopenurl: Failed for Url: "Fbauth2:///" - Error: "(Null)"
Can Siri Be Invoked Programmatically Within My App Using Private APIs
Printing the View in iOS with Swift
How to Center Crop an Image in Swiftui
Swiftui - Detect When Scrollview Has Finished Scrolling
How to Calculate the Age Based on Nsdate