Reputation: 121
I'm creating an application on the iPad. I create a custom keyboard using UITextField
's inputView
property. To insert text at the cursor position, I use the copy & paste method (http://dev.ragfield.com/2009/09/insert-text-at-current-cursor-location.html), which works fine. Now, I want to create the delete key. The code that I'm using is:
if (textField.text.length > 0) {
textField.text = [textField.text substringToIndex:textField.text.length-1];
}
However, as you may know, it only deletes the last character no matter where the cursor is. Does anyone know a better solution?
Thank you very much!
Upvotes: 12
Views: 10637
Reputation: 8002
Just call [textField deleteBackward]
. It takes care of cursor position and highlight for you.
Swift:
textField.deleteBackward()
Upvotes: 18
Reputation: 1915
To delete the position behind the cursor, you can use textField.deleteBackward()
This is what I use in Swift 5 when I want to get the result without deleting text from the UITextField
extension UITextField {
/// simulates removing a character from 1 position behind the cursor and returns the result
func backSpace() -> String {
guard var text = text, // local text property, matching textField's text
let selectedRange = selectedTextRange,
!text.isEmpty
else { return "" }
let offset = offset(from: beginningOfDocument, to: selectedRange.start)
let index = text.index(text.startIndex, offsetBy: offset-1)
// this doesn't remove text from the textField, just the local text property
text.remove(at: index)
return text
}
}
Upvotes: 0
Reputation: 3138
you can try this:
if (txtTotal.text.length > 0) {
txtTotal.text = [txtTotal.text substringToIndex:txtTotal.text.length-1];
}
Upvotes: -1
Reputation:
Late to the party (again ;-)... With iOS 5, UITextField
conforms to the UITextInput
protocol, which extends UITextField
with some helpful methods and properties, including the selectedTextRange
property, which is the equivalent of selectedRange
in UITextView
.
Upvotes: 5
Reputation: 34
What about this if (UITextField.text.length > 0) { [UITextField deleteBackward]; }
:)
Upvotes: -1
Reputation: 385610
Holy necro, Batman! Here's a much simpler answer for iOS 3.2 and later. Do this in your view controller's viewDidLoad
or some other method that has access to the delete button:
[self.myDeleteButton addTarget:nil action:@selector(deleteBackward) forControlEvents:UIControlEventTouchDown];
This is the same way the system keyboard's delete key works: it sends the deleteBackward
message along the responder chain.
Upvotes: 0
Reputation: 45108
This is an alternative solution using a undocumented API: selectionRange
. I don't know if this will pass Apple's review but as written it won't make the app crash if the method is not available and does not give warnings too :)
This is a category on UITextField:
- (void)deleteBackward{
@try{
//check current selected range
NSRange selectedRange = [[self valueForKey:@"selectionRange"] rangeValue];
if (selectedRange.location == NSNotFound) selectedRange = NSMakeRange([[self text] length], 0);
if (selectedRange.location < 1) return;
//delete one char
NSRange deleteRange = (selectedRange.length>0)?selectedRange:NSMakeRange(selectedRange.location-1,1);
self.text = [self.text stringByReplacingCharactersInRange:deleteRange withString:@""];
//adjust the selected range to reflect the changes
selectedRange.location = deleteRange.location;
selectedRange.range.length = 0;
[self setValue:[NSValue valueWithRange:range] forKey:@"selectionRange"];
}@catch (NSException *exception) {
NSLog(@"failed but catched. %@", exception);
}@finally {}
}
in iOS5 UITextField and UITextView conform to UITextInput protocol (which conforms to UIKeyInput) so you can do [textField deleteBackward];
which will do exactly the same as Del
key in the keyboard, [textField insertText:@"text"];
which will insert text and update the caret position correctly, etc.
So, for compatibility purposes, probably what you want to do similar to this:
- (void) myDeleteBackward
{
if ([self conformsToProtocol:@protocol(UITextInput)]) {
// iOS5 and later
[textField deleteBackward];
// Or do below line if you are not deploy-targeting 5.0 or above and want to avoid warnings
//[textField performSelector:@selector(deleteBackward)];
} else {
// iOS4 and older versions
// Do the trick :)
@try{
...
}@catch (NSException *exception) {
...
}
}
}
Upvotes: 4
Reputation: 607
I've got it!
This is my delegate method implementation for the shouldChangeCharactersInRange
method.
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange) range replacementString:(NSString *) string {
if ([string isEqualToString:@"⌫"]) {
// NSLog(@"Backspace Pressed");
NSMutableString *text = [textField.text mutableCopy];
// NSLog(@"Length: %d Location: %d", range.length, range.location);
if (range.length > 0) {
[text deleteCharactersInRange:range];
}
if (range.length == 0 && range.location != 0) {
NSRange backward = NSMakeRange(range.location - 1, 1);
// NSLog(@"Length: %d Location: %d", backward.length, backward.location);
[text deleteCharactersInRange:backward];
}
// NSLog(@"%@", text);
textField.text = text;
return NO;
} else {return YES;}
}
It works hand in hand with the UIPasteboard method for getting text into a UITextField
, which means that you have to link up your delete key to a method that pastes an arbitrary unicode character into your textfield (such as ⌫
), and when the delegate method is called, you recognise that the replacement string is that specific character.
From there, you either delete the characters in range
from your mutable string of the textField's text if there is an active selection, or you grab the previous character from the range if there is no selection, just a caret.
Upvotes: 5
Reputation: 624
Consider switching to a UITextView
, which has a selectedRange
property for getting the currently selected range of characters or the cursor location if nothing is selected. Unfortunately, UITextField
does not have this method, and I have not found another way to find the cursor location.
The documentation for the selectedRange
property can be found here here on Apple's website. It consists of an NSRange
in which selectedRange.location
is the cursor location and selectedRange.length
is the number of selected characters (or zero if nothing is selected.) Your code will have to look something like this:
textView.text = [textView.text stringByReplacingCharactersInRange:textView.selectedRange withString:@""];
Upvotes: 2
Reputation: 53669
A UITextView has a selectedRange
property. Given that you could build a range to use with the following code:
textView.text = [textView.text stringByReplacingCharactersInRange:?? withString:@""];
A UITextField has no such range property. Obviously it has a _selectionRange
member but that is private.
I think your choices are either to switch to a UITextView or prevent having the cursor anywhere but at the end of the text and using your current code.
You can always submit a bug report to Apple requesting that they document selectedRange
for UITextField, or ask for special permission to access the field directly.
Upvotes: 0