UITextView clear selection when touching outside - ios

There is UITextView which is selectable but not editable.
When I highlight text and touch outside the selection is not cleared.
I tried to use UIMenuControllerWillHideMenu, it helps to clear selection when I touch other as the menu controller dismiss. But the problem is when I change the selection the selection is cleared because the menu controller dismissed and re appear after the selection modification.
Has anyone workaround this problem too?

Add UITapGestureRecognizer and call endEditing:YES on your UITextView.
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onTextViewTap:)];
- (void)onTextViewTap:(UITapGestureRecognizer *)tapGesture {
if (tapGesture.state == UIGestureRecognizerStateEnded) {
self.textView.selectedTextRange = nil;
}
}

Related

No touch event working when keyboard appears (only when view is animated)

I have added functionality when keyboard appears we will up cause keyboard hides most part of ipad, but when view is up no touch event works, main motive to dismiss keyboards when tap or touch outside
below is screenshots shows I can't touch outside I have to use done button
You will need to create a UITapGestureRecognizer!
First of all define a UITapGestureRecognizer in your header (.h) file.
Then in the viewDidLoad:
tapGesture =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(closeKeyBoard)];
[self.view addGestureRecognizer:tapGesture];
Now the method which closes the keyboard:
-(void)closeKeyBoard {
[self.view endEditing:YES];
}
That's all you need!
Cheers

Clear button (x) of textfield not working if auto keyboard hiding is used at the same time

I'm using a gesture recognizer like this solution to hide the keyboard if the user taps outside of one of my textfields. In my case I'm using a scroll view with some textfields on top. There is also some auto-scroll feature implemented (that's why I'm using the scroll view).
I can hide the keyboard if the user taps outside of it. This is working. I have also enabled the clear button (x button on the right) of the textfield. If the user taps on it the keyboard is hidden, but the content of the textfield is not cleared. Normally I would expect that the content is cleared and the keyboard is not dismissed in this case. This problem was also found by Patrick.
I tried to get the tapped object of the UITapGestureRecognizer, but this seems to be the UIScrollView. How can I get the clear button and the auto keyboard hiding feature working?
A generic solution would be nice that would work for all textfields. To complete my question I add my code (which is in C#):
UITapGestureRecognizer tapGesture = new UITapGestureRecognizer ();
tapGesture.CancelsTouchesInView = false;
tapGesture.AddTarget (() => HandleSingleTap (tapGesture));
this.scrollView.AddGestureRecognizer (tapGesture);
private void HandleSingleTap(UITapGestureRecognizer recognizer){
this.scrollView.EndEditing(true);
}
You can of course provide your solutions for Objective-C.
you should be able to convert the tap location from the gestureRecognizer so you can see if the textField was tapped
I didn't verify it but something like this should work:
- (void)handleTap:(UITapGestureRecognizer *)sender {
BOOL tappedTextField = NO;
UIScrollView *scrollView = (UIScrollView *)sender.view;
for (UITextField *textField in self.textFields) {
CGRect textFieldBounds = textField.bounds;
CGRect textFieldFrameInScrollView = [textField convertRect:textFieldBounds toView:scrollView];
CGPoint tapLocationInScrollView = [sender locationInView:scrollView];
if (CGRectContainsPoint(textFieldFrameInScrollView, tapLocationInScrollView)) {
tappedTextField = YES;
break;
}
// Might work as well instead of the above code:
CGPoint tapLocationInTextField = [sender locationInView:textField];
if (CGRectContainsPoint(textField.bounds, tapLocationInTextField)) {
tappedTextField = YES;
break;
}
}
if (!tappedTextField) {
// handle tap
}
}

Hide UITableView on touches outside the tableview

I have a small UITableView that is hidden when the view is loaded. When i click on "SHOW" UIButton, the UITableView is made visible by myTableView.hidden=NO;
I want to hide UITableView when a user touches outside its frame. Thanks for any help!
Best Approach
Simple.Before show up the UITable View add one more grayed out/Transparent view then add tap gesture recogniser on it to hide it . That's it.
Show Overlay View first - alpha will be 0.5f and background color should be clear color.
show the table view.
NOTE: over lay view should have tap recogniser which will hide the overlay and table view
in View did load
UITapGestureRecognizer *tapRecog = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(overlayDidTap:)];
[myOverLayView addGestureRecognizer:tapRecog];
- (void)overlayDidTap:(UITapGestureRecognizer *)gesture
{
//hide both overlay and table view here
}
Bad Approach
We should not add tap recogniser on main view itself. Because it may have lots of
controls inside of it. so when user tap on it. it will perform its operation. So to avoid
it we can simulate the same behaviour by above approach
You can get touch position by this:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[self.view addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:self.View];
}
Then just check if the point is in tableview frame. If not then hide the tableview. Hope this help. :)
Subclass UITableView, override pointInside:withEvent:. It is templated for this reason.
Something like:
-(BOOL)pointInside:(CGPoint) point withEvent:(UIEvent*) event
{
BOOL pointIsInsideTableView = [super pointInside:point withEvent:event];
BOOL pointIsOutsideTableView = // Some test
return pointIsInsideTableView || pointIsOutsideTableView;
}
So you can catch the touch in table view implementation, where it belongs logically in this case.

UITextView double tap to edit

So I have a UITextView I'm using to make a moveable, editable label (My prior searches on SO showed this to apparently be the best option). I need to have the user double tap to enable editing and set it to become the first responder. I can't find a way to do this, and all my other searches have turned up either outdated answers or vague answers. Nothing I've tried seems to work. I've tried using the UITextViewDelegate to have it start editing as opposed to selecting text using textViewDidChangeSelection:, but it doesn't work until you change the current selection. I also tried using a custom UITapGestureRecognizer like so:
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[doubleTap setNumberOfTouchesRequired:1];
[newLabel addGestureRecognizer:doubleTap];
-(void)doubleTap:(UITapGestureRecognizer *)sender
{
NSLog(#"Double tap detected");
NSLog(#"Sender view of class %#", [[sender view] class]);
UITextView *tappedView = (UITextView *)[sender view];
[tappedView setEditable:YES];
[tappedView becomeFirstResponder];
// [tappedView setEditable:NO];
}
The double tap gesture is never called. I'm not sure why. Strangely, it also doesn't select text either while it's like that. It seems to just break double tap gestures. Is there a way to get rid of the standard double tap selection gesture, or to modify it? Should I subclass UITextView and, if so, what would I change?
I found a neat solution, with less code (Swift 4.2):
Create a Custom UITextView Class and in it write this
override var canBecomeFirstResponder: Bool {
if self.isEditable {
return true
} else {
self.isEditable = true
return false
}
Then in viewDidLoad() write the following (or deselect 'Editable' under behaviour in the storyboard editor)
myTextView.isEditable = false
Then simply put the same code somewhere when you're finished editing the text - eg. textViewDidEndEditing(_ textView: UITextView)
myTextView.isEditable = false
When the view loads, the textView is not editable and all data detectors work. A second tap then allows it to be edited (and disables the data detectors).
As soon as you exit the textView, it's set to not editable again and the data detectors work.
All this without any gesture recognisers! :-D
Sublassing UITextView, I added this method to the .m file.
-(BOOL)canBecomeFirstResponder
{
if (self.editable == YES){
return YES;
}
else{
return NO;
}
}
In addition to this, I used
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGesture
{
return YES;
}
This is the best way I found to solve my problem. I only wanted to allow double tapping to edit. I wanted no text selection, scrolling, etc to happen until it was double tapped. To futher finish this, you'll need a to use a UITextViewDelegate to turn textView.editable = NO
-(void)textViewDidEndEditing:(UITextView *)textView
{
[textView setEditable:NO];
}
You should set the target of the Gesture Recognizer as the textfield.
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:textField action:#selector(doubleTap:)];

GestureRecognizer Interferes w/ MapKit Popup

I have a simple MapKit app working fine in iOS. It has annotation and when the user clicks on them, the little gray default popup is displayed with the title / subtitle. I even added a UIButton view into it.
So the problem is, I have a search bar above my map. I wanted to resignFirstResponder from the search box whenever the user clicks on the MapView, so I added a simple tap gesture responder. Worked great except now the little gray detail popups no longer show up (only the annotation pins)! I can still tap, zoom, move around etc. Just no popups.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
tap.cancelsTouchesInView = NO;
tap.delaysTouchesBegan = NO;
tap.delaysTouchesEnded = NO;
[mapView addGestureRecognizer:tap];
-(IBAction)tapped:(UITapGestureRecognizer *)geture {
[searchBar resignFirstResponder];
}
Is it possible to have the best of both worlds?
I used a delegate method similar to the following to arbitrate between touches that should go to my custom view's pan gesture recognizer and touches that should go to the scroll view that contained my custom view. Something like it might work for you.
// the following UIGestureRecognizerDelegate method returns YES by default.
// we modify it so that the tap gesture recognizer only returns YES if
// the search bar is first responder; otherwise it returns NO.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ((gestureRecognizer == self.tapGestureRecognizer) &&
(gestureRecognizer.view == self.mapView) &&
[searchBar isFirstResponder])
{
return YES; // return YES so that the tapGestureRecognizer can deal with the tap and resign first responder
}
else
{
return NO; // return NO so that the touch is sent up the responder chain for the map view to deal with it
}
}

Resources