I have a UITextView configured with a delegate. I've enabled editing attributes by setting allowsEditingTextAttributes to YES.
When the user types a character in the text view, the delegate receives the textViewDidChange: message.
But when the user changes an attribute (such as making a selection and tapping Bold or Italic), no textViewDidChange: message.
The documentation specifically says that textViewDidChange: should receive a message when the user changes attributes:
Tells the delegate that the text or attributes in the specified text view were changed by the user.
But it's not working for me. What am I missing here?
I tested this scenario in iOS 6 and had the exact same outcome: attribute changes from the "select" pop-up did not trigger the textViewDidChange: method. It seems that this is a bug or the documentation needs to clarify what type of attribute change would trigger this event.
A possible workaround is to implement the textViewDidChangeSelection: method. It gets called whenever a selection is made (which the user would have to do before changing an attribute). Check to see if the selectedRange.length is > 0 (which would mean an actual word has been selected, instead of just moving the cursor around), and save that selectedRange. Once the length is zero again, it means they deselected the item. At that time, you could take the previous range and work with the text.
- (void)textViewDidChangeSelection:(UITextView *)textView
{
static BOOL rangeSet = NO;
static NSRange mySelectedRange;
if( textView.selectedRange.length > 0 && !rangeSet )
{
mySelectedRange = textView.selectedRange;
rangeSet = YES;
}
else if( textView.selectedRange.length == 0 && rangeSet)
{
// Work with text
NSLog(#"Working with previously select text: %d, %d", mySelectedRange.location, mySelectedRange.length);
}
}
In documentation it has also been mentioned that
This method is not called in response to programmatically initiated changes
So if you are setting bold or italic programatically so it will not invoke this delegate method
Please check if you've set UITextViewDelegate in in your .h file. Also you'll have to `make
yourTextView.delegate = self
So that your Text View will give control to your current class.
I got around this by subclassing UITextView, overriding the toggleBoldface:, toggleItalics: and toggleUnderline: methods, and calling [self.delegate textViewDidChange:self] from those methods. This answer helped me figure that out.
Related
What's the easiest way to have an NSTextField with a "recommendation list" dynamically shown below it as the user types? Just like Safari's address bar that has a menu of some sorts (I'm pretty confident Safari's address bar suggestions is menu since it has rounded corners, blue gradient selection, and background blurring).
I've tried using NSTextView's autocompletion facility but found it was inadequate:
It tries to complete words instead of the whole text fields – in other words, selecting an autocomplete suggestion will only replace the current word.
It nudges the autocompletion list forward and align it with the insertion point instead of keeping it align with the text field.
In the sample screenshot above whenever I selected the autocomplete suggestion the text field only replaces K with the suggested item in the list, which results in Abadi Abadi Kurniawan.
These are what I'd like to achieve:
Whenever a suggestion is selected, the entire text field is replaced with the suggestion.
Keep the suggestion list aligned with the text field's left side.
Note: This is not a question about adding progress indicator behind a text field.
The Safari address bar uses a separate window. Apple has example project CustomMenus and it only takes an hour or two to customize it.
Developer session explaining what has to be done Key Event Handling in Cocoa Applications
If you want to be able to select multiple words you need to provide own FieldEditor (credits should go for someone else)
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(nullable id)client;
{
if ([client isKindOfClass:[NSSearchField class]])
{
if (!_mlFieldEditor)
{
_mlFieldEditor = [[MLFieldEditor alloc] init];
[_mlFieldEditor setFieldEditor:YES];
}
return _mlFieldEditor;
}
return nil;
}
- (void)insertCompletion:(NSString *)word forPartialWordRange:(NSRange)charRange movement:(NSInteger)movement isFinal:(BOOL)flag
{
// suppress completion if user types a space
if (movement == NSRightTextMovement) return;
// show full replacements
if (charRange.location != 0) {
charRange.length += charRange.location;
charRange.location = 0;
}
[super insertCompletion:word forPartialWordRange:charRange movement:movement isFinal:flag];
if (movement == NSReturnTextMovement)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"MLSearchFieldAutocompleted" object:self userInfo:nil];
}
}
This only addresses half of your answer, but I believe you need to subclass NSTextView and implement the - (NSRange)rangeForUserCompletion method, returning the range of the entire string in the text field. This should make sure that it doesn't just autocomplete the most recently entered word.
If you want a custom menu, you're going to have to do that yourself, probably by implementing the -controlTextDidChange: method and displaying a custom view with a table when appropriate.
I have a tableview with around 100 text fields inside it. I added only one text field. It is reused and it is accessed using tag.
The problem is this: suppose the user has changed some textfield. Now, I want to access that text field changes during saving of the data.
How can I do this?
You are very near to your goal. You have already assigned tag to your UITextField. You can use and track tag in this delegate method.
-(void)textFieldDidEndEditing:(UITextField *)textField
{
}
First set tag of textfield with indexpath.row
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// replace text in your array
}
I have text field in that i have to some functionality click on back space button in keyboard when the text field is empty ...shouldChangeCharactersInRange is calling when the textfield has some text.how call solve this problem.
You can catch that key in
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
It is not written explicitly in the docs but if you press the backspace key then the last parameter string will have a length of 0.
At least this worked for me when using UITextView objects.
Hope this helps :)
You should read the documentation of UITextField... By the way here it is from the documentation of UITextField
textFieldShouldClear:
Asks the delegate if the text field’s current contents should be removed.
- (BOOL)textFieldShouldClear:(UITextField *)textField
Parameters
textField
The text field containing the text.
Return Value
YES if the text field’s contents should be cleared; otherwise, NO.
Discussion
The text field calls this method in response to the user pressing the built-in clear button. (This button is not shown by default but can be enabled by changing the value in the clearButtonMode property of the text field.) This method is also called when editing begins and the clearsOnBeginEditing property of the text field is set to YES.
Implementation of this method by the delegate is optional. If it is not present, the text is cleared as if this method had returned YES.
Availability
Available in iOS 2.0 and later.
Declared In
UITextField.h
If the text field is or becomes empty, put a space character in it. If you detect a backspace, and the dummy space character is the only thing in the text field, don't delete it (yet). When finally reading out the contents of the text field, remove the spurious leading space if you added one.
i have two UITextView items, how can i fetch what is written using a button on iphone?
Imagine something like a translate app, the user enters a word in UITextView 1 and by pressing the button the UITextView 2 is getting filled with data.
UITextView has a property text. Simply use this.
Set up IBOutlets for textView1 and textView2. Then have the button do something along these lines:
-(IBAction)moveTextOver:(id)sender {
[textView2 setText:textView1.text];
}
To get fancier, you can have a method -(NSString *)transformText:(NSString *)text that translates or does whatever you like. Then use
-(IBAction)moveTextOver:(id)sender {
[textView2 setText:[self transformText:textView1.text]];
}
Create an IBAction method that is linked to a button and in that method read the "text" property of the textView or textField, do your calculations on it and assign the results to the text property of thee second field.
I have a textbox in which I wanted a user to enter only numbers. I have implemented the number keypad there. But if someone puts my app in the background and copies some character string from some other app and comes back to my app and pastes it, it successfully pastes the string content into my numeric textfield. How can I restrict this scenario?
#theChrisKent is close, but there's a slightly better way. Use the delegate method -textView:shouldChangeTextInRange:replacementText:. Check if replacementText contains any non-numbers, and if so return NO.
You can disable pasting altogether by following the top answer on this question: How disable Copy, Cut, Select, Select All in UITextView
Just subclass the UITextView and override this method (code stolen from above question):
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == #selector(paste:)
return NO;
return [super canPerformAction:action withSender:sender];
}
Otherwise you can implement the UITextViewDelegate protocol and implement the textViewDidChange: method and check if it's numeric. If not, undo the changes. Documentation here: http://developer.apple.com/library/ios/documentation/uikit/reference/UITextViewDelegate_Protocol/Reference/UITextViewDelegate.html#//apple_ref/occ/intfm/UITextViewDelegate/textViewDidChange: