UITextView setSelectedRange changes editable property - ios

From the start, my UITextView with editable property to true is not editable (via settings in a NIB). The behaviour is such that a user can select and copy text but not edit. This is the way things should be.
However, if I make a call to setSelectedRange, a side effect is that the editable property is set to YES.
Setting it back to NO [textview setEditable:NO] scrolls to the bottom of the textView and undoes my programmatic selection. It also doesn't work, as editing becomes enabled anyway. The keyboard appears and everything.
I need to be able to select something programmatically and keep the textView in a state where users can only copy and select text.
[textView select:self];
[textView setSelectedRange:selectedText];
I'm stuck. Looking for any advice you can give.
This doesn't work:
[textView select:self];
[textView setSelectedRange:selectedText];
[textView setEditable:NO];
I've also tried setting the delegate function textViewShouldBeginEditing to return NO:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
return NO;
}
That just locks everything down and I can't select any text.

I realize this has already been answered, but here is an improvement I made to keep the popout menu, just disable certain options;
-(BOOL) canPerformAction:(SEL)action withSender:(id)sender {
bool response = [super canPerformAction:action withSender:sender];
if(response && (action == #selector(cut:) || action == #selector(paste:) || action == #selector(delete:) || action == #selector(_promptForReplace:))) {
return NO;
}
return response;
}
canPerformAction is called per defined action. Calling the parent method will take care of most of these cases, but I have also decided to disable cut,paste,delete and spelling suggestions (_promptForReplace).

This appears to work for me in a similar situation:
just let the textview be editable
[textView setDelegate:self];
[textView select:self];
[textView setSelectedRange:range];
add a function (BOOL)textView:shouldChangeTextInRange:replacementText: returning NO
and the final trick: assign an empty view as a keyboard for the textview, using:
textView.inputView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];

The textView should be editable:
[textView setEditable:YES];
Do the selection:
[textView select:self];
[textView setSelectedRange:range];
Have these in the delegate:
To disable the menu (not ideal for me but it's ok):
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;
return NO;
}
To disable the keyboard:
textView.inputView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
To disable editing:
- (BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
return NO;
}

Related

Textfieldshouldreturn auto scroll screen

I use the code below. As it seems I have 5 uitextfields. Now for some reason when I clicked next, the view actually scrolled down automatically so I could see the textfield I was writing data with the keyboard. I thought this was default.
I added a lot of code in the uiview and added a button linking to another view. Somehow in the middle of that process my uiview lost its "auto-scroll-when-next-is-pressed" mechanism. I tried deleting my button and messed around a bit but couldn't find the problem.
Not sure if I should post the whole class.
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
[textField resignFirstResponder];
if (textField == self.firstOne) {
[self.secondOne becomeFirstResponder];
} else if (textField == self.secondOne) {
[self.thirdOne becomeFirstResponder];
} else if (textField == self.thirdOne) {
[self.fourthOne becomeFirstResponder];
} else if (textField == self.fourthOne) {
[self.fifthOne becomeFirstResponder];
}
return NO;
}
I also found some content on how to scroll screen programmatic by setting up coordinates. Not very viable in my opinion. I want it to be the way it was "Knowing where to scroll down automatically".
I found out that the reason is I added viewWillAppear method when I introduced the new button. That code didn't call the super method, so by just adding 1 line of code the problem was fixed
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// your code
}
I hope that add the ScrollView in View and next step add the 5 TextField in SubView of the UIScrollView such like as
[scrollView addSubView:textField1];
Next increase and decrease the scrollview content of set. Such as
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[scrollView setContentOffset:CGPointMake(0, 230) animated:YES];
}

Disable Keyboard for UITextfield

I'm wondering how to disable the inputview of a UITextfield. Setting textField.inputView = nil; or [textField setInputView:nil] in ShouldBeginEditing doesn't do anything, and using the userInteraction property removes the ability to interact with the field. Ideally, I'd like to remove both the cursor and the keyboard while still being able interact with and switch between textfield methods, using ShouldBeginEditing and ShouldEndEditing. Is there any way to accomplish this?
You should do this:
myTextField.inputView = UIView.new; //Empty UIView
Setting it to nil just means the default keyboard is used.
To get rid of the caret, subclass the UITextField and override caretRectForPosition:
- (CGRect) caretRectForPosition:(UITextPosition*)position
{
return CGRectZero;
}
Try this :
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return NO; // Hide both keyboard and blinking cursor.
}
or
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[textField resignFirstResponder]; // hides keyboard
}

How to show Xbutton(clear button) always visible in uisearchbar [duplicate]

This question already has answers here:
Adding the "Clear" Button to an iPhone UITextField
(11 answers)
Closed 2 years ago.
In my application, I am adding a UISearchBar.
My intent is to enable the UISearch Bar "X button"(clear button in UITextField) to be always visible.
I have tried using the following code below to try to make the "X Button" be always visible. However, it does not work. If I set tf.clearButtonMode = UITextFieldViewModeNever, the clear button in uitextfield not showing. I am not sure what is wrong?
I would really appreciate anyone's help here. Why is this not working?
Code (Not working)
for (UIView* v in searchBar.subviews)
{
if ( [v isKindOfClass: [UITextField class]] )
{
UITextField *tf = (UITextField *)v;
tf.delegate = self;
tf.clearButtonMode = UITextFieldViewModeAlways;
break;
}
}
Goal:
I want to always show the clear button if the text length is equal to 0
i.e. if I don't input any text.
UITextField *searchBarTextField = nil;
for (UIView *subview in self.searchBar.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
searchBarTextField = (UITextField *)subview;
searchBarTextField.clearButtonMode = UITextFieldViewModeAlways;
break;
}
}
This is the default behavior of the search bar. Because if the UITextField is blank then there is no need to press it.
U can do it in Xib. I am attaching the screenshot.
And programmatically
myUITextField.clearButtonMode = UITextFieldViewModeAlways;
I tried to get it but unfortunately , There is no Way of Customising with the ClearButton(X) of UITextField .
There is a way that If You only need it to get resign the KeyBoard , Then just overriding this method :
Just clear the field yourself and call resignFirstResponder .
-(BOOL)textFieldShouldClear:(UITextField *)textField
{
textField.text = #"";
[textField resignFirstResponder];
return NO;
}
Documentation about it HERE
This is an older question but I came here with an equal customer request: "Show the clearButton as soon as the cursor is in the searchField. We want to be able to cancel the search with this button in any stage".
I came up with a solution other than adding a custom button:
AppleDocs:
UITextFieldViewModeAlways The overlay view is always displayed if the
text field contains text.
So adding a whitespace as the first character will set the clearButton active.
The leading whitespace can be removed as soon as text is entered in the searchField or at any other point before using the text.
-(void)textFieldDidBeginEditing:(UITextField *)textField{
//adding a whitespace at first start sets the clearButton active
textField.text = #" ";
}
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
...
NSString *completeNewString = [textField.text stringByReplacingCharactersInRange:range withString:string];
//remove the dummyWhitespace (here or later in code, as needed)
self.searchString = [completeNewString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
...
return YES;
}

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:)];

UITextView can't dismiss the keyboard in programmatically-created UITableView

There seems to be lots on this subject. But I couldn't get any of the solutions to work.
My code creates a tableView full of cells with varying contents (based on a JSON), the user should enter the info in each cell. The problem I am having is, when the user taps somewhere outside the cell (i.e. on the tableView background) I want the keyboard to dismiss.
didSelectRowAtIndexPath: method is not good.
touchesBegan: does not fire at all (tableView has user interaction enabled, but I assume there is some other reason).
I have added a gesture to the tableView, but then I cannot start editing.
I know the resignFirstResponder. But I don't know which field is being edited. so I think, I need to go with the endEditing: method. But I just couldn't get it called, when user touches outside of a cell.
Any help would appreciated.
If that is a textField as #JFS said, you can set the delegate and resign it in this below method.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
Else If that is a textView, You can add a toolbar with done button as inputAccessoryView to your textView and resign your textView.
I am having two more ideas
Bad Idea:
Try to make an invisible button in the cell background and add an action method to resign it. But this will get confused, when you are using didSelectRowAtIndexPath: method of your UITableView.
Good Idea:(Good one)
UITableView surely will have UIScrollview. So in the scrollViewDidScroll: method, set [self endEditing:YES] will surely work.
Good Idea 2
Create a new View or Button and place it on top of the all views, when a textView is in editing and call the endEditing: method when user touches the view or button.
TO GET A TOUCH DETECTION IN TABLEVIEW:
Some of these Q&A will help you.
https://stackoverflow.com/a/8787019/1083859
Why does my UITableView not respond to touchesBegan?
https://stackoverflow.com/a/8786706/1083859
Okay after lots of playing around a managed to figure (something) out, it is not great but works.
Most of the gaps around the table is taken up by section headers (a small amount by the cell walls). To get these areas to call a method I added a gesture to the section header like this;
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil)
{
return nil;
}
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(20, 8, 320, 20);
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor colorWithRed:76/255.0 green:86/255.0 blue:108/255.0 alpha:255/255.0];
label.shadowColor = [UIColor grayColor];
label.shadowOffset = CGSizeMake(-0.0, 0.0);
label.font = [UIFont boldSystemFontOfSize:16];
label.text = sectionTitle;
UIView *view = [[UIView alloc] init];
[view addSubview:label];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(eventMenuTap)];
[view addGestureRecognizer:singleTap];
return view;
}
This also enabled me to customize the label for each section. The net reseult is now I have the keyboard closing when the table is scrolled and if (nearly) anywhere is clicked outside of a cell (i.e. a header) then the eventMenuTap is called.
-(void)eventMenuTap
{
NSLog(#"Tap has begun...");
[self.view endEditing:YES];
}
Thanks for all the ideas and help with this.
For any passersby, the simplest and most effective solution I have found requires 2 things:
1: Subclass your table view and add the following to its .m:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// send your own dismiss message; you can use self.delegate to refer to TV's TVC...
[((SearchVC *)((UITableViewController *)self.delegate).parentViewController).searchBar resignFirstResponder];
// crucial!
[super touchesBegan:touches withEvent:event];
}
2: Add the following to your TVC:
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// send your own dismiss message...
[((SearchVC *)self.parentViewController).searchBar resignFirstResponder];
}
This works beautifully for me. I initially tried adding touchesBegan to my subclassed cell, but found that was insufficient and, after adding these two things, superfluous.

Resources