Custom keyboard backspace button - ios

I've created a custom keyboard with my own Unicode characters... The app works great but when I press the back space it will sometimes not backspace and other times it will.. and often after I've gotten it to delete the previous character with my backspace the other letters buttons will no longer type the unicode characters I want...
Here is one of my Unicode characters code:
textViewString = [[NSString alloc] initWithFormat:#"%#%#", textView.text, char6String];
[textView setText:textViewString];
Where "char6string" would just be one of my unicode characters in this case "π"
Here is the backspace buttons code:
if ([textView.text length]>0) {
textView.text = [textView.text substringToIndex:([textView.text length]-1)];
}

I'm doing something similar in one of my apps and haven't seen any issues by using setText: rather than textView.text =.
NSUInteger length = [self.textField.text length];
if (length>0) {
[self.textField setText:[text substringToIndex:length-1]];
}
Hope this helps!

Well, I figured out the problem and it's a messy solution.. for whatever reason when you trio to add any of the new unicode characters that came out about 4 months ago to a text field via code it adds that unicode character along with a weird glitches unicode character that doesn't exist resulting in uncopyable text and 2 characters added... so now I need to detect if when a button was pressed to add a character if it changes the length by 1 or 2 and if it changes the length by 2 it's a new unicode character and I need to do an auto-delete then and there, otherwise if it only increases by one it's fine and I don't need to do anything!
My new add character to textView string looks like this for each button:
length1 = [textView.text length];
textView.text = [textView.text stringByAppendingString:char1String];
length2 = [textView.text length];
if (((length2)-(2))==length1) {
[textView setText:[textView.text substringToIndex:length2-1]];
}

Related

Find text in array and return index number

I am displaying an array of strings separated by \n or linebreaks in a textview. Thanks to the \n, if there is room in the textview, each string gets its own line. However, if the width of the textview is less than the string, then the textview automatically wraps the line to the next line so that the string in effect takes two lines. Nothing wrong with this so far.
However, I want to grab the string if someone touches it. It works fine if the string fits on a line. However, if the string has been broken across two lines by textview, if the user touches the top line, I need to attach the line below to get the whole string. Or if the user touches the bottom line, I need to get and add the previous one to have a whole string.
Can anyone suggest proper way to do this?
Here is my code that grabs the line the person touches, however, it only gets the line touched and fails when it tries to calculate the index of the string in the array.
Thanks for any suggestions:
- (void) handleTap:(UITapGestureRecognizer *)recognizer{
UITextView *textView = (UITextView *)recognizer.view;
CGPoint location = [recognizer locationInView:textView];
CGPoint position = CGPointMake(location.x, location.y);
UITextPosition *tapPosition = [textView closestPositionToPoint:position];
UITextRange *textRange = [textView.tokenizer rangeEnclosingPosition:tapPosition withGranularity:UITextGranularityLine inDirection:UITextLayoutDirectionRight];
//In following line, I am not getting the full text in the string, only the text of that line. I need to get the whole string.
NSString *tappedLine = [textView textInRange:textRange];
NSArray* myArray = [self.listSub.text componentsSeparatedByString:#"\n"];
NSInteger indexOfTheObject = [myArray indexOfObject: tappedLine];
//If the tapped line is not the same thing as the string, the above index becomes huge number like 94959494994949494 ie an error, not the index I want.
}
This is indeed possible.
First, you need to change the granularity to UITextGranularityParagraph:
UITextRange *textRange = [textView.tokenizer rangeEnclosingPosition:tapPosition withGranularity:UITextGranularityParagraph inDirection:UITextLayoutDirectionRight];
This will return you the entire wrapped line of text that the user tapped, no matter where they tapped it.
However, this text will include the trailing \n character that marks the end of the paragraph. You need to remove this before comparing the text to your array. Replace the last line of your code above with these two lines:
NSString *trimmedLine = [tappedLine stringByTrimmingCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
NSInteger indexOfTheObject = [myArray indexOfObject: trimmedLine];
You may want to look into using a UITableView
https://developer.apple.com/documentation/uikit/uitableview
you could create a cell with a text view for each entry in the array and you will get delegate calls when a user interacts with any of the cells

What's the best way to add a left margin to an NSAttributedString?

I'm trying to add a left hand margin to an NSAttributedString so that when I concatenate it with another NSAS, there is a bit of space between the two box frames.
All I have so far is this:
NSMutableAttributedString *issn = [[NSMutableAttributedString alloc] initWithString:jm.issn attributes:nil];
NSRange range = NSMakeRange(0, [issn length]);
[issn addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"AvenirNext-Medium" size:8]
range:range];
NSMutableAttributedString *textLabel = [[NSMutableAttributedString alloc] initWithAttributedString:title];
[textLabel appendAttributedString:issn];
I want the margin on the left side of the second string.
Thanks!
Edit: image upload
Why not just use a tab character between the two strings?
You could do this by changing your first line to this:
NSMutableAttributedString *issn = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"\t%#", jm.issn] attributes:nil];
This should output something like like what you want. You may, however, want to add 2 \t characters instead of one because depending on the string length, it may not need a tab character to align it (for example, in that exact string you posted, it didn't add anything to my output).
1 tab with your string:
2 tabs with your string:
You can't. If you're concatenating attributed strings then there is no "margin" around a specific range in the final string. How would that work with multiple lines or text wrapping?
If you want clear space within an attributed string, use white space characters - spaces or tabs. You can define the position of tab stops using paragraph styles.
All you can do is, add the required spaces(or whitespace characters) before the source string and then add it to your NSMutableAttributedString.
NSString *newString = [NSString stringWithFormat:#" %#", jm.issn] <- Have given two spaces here.
Thanks

iOS6 failed to check string contains only alpha-numeric chars

I am using this code to check if a user input string contains only alpha-numeric chars in iOS6:
NSCharacterSet *alphaSet = [NSCharacterSet alphanumericCharacterSet];
NSString *trimmedString = [text stringByTrimmingCharactersInSet:alphaSet];
BOOL valid = [trimmedString isEqualToString:#""];
but here's the result of running this piece of code:
Note that the text (string to be checked) contains only Chinese chars, but after trim by alphaSet it becomes an empty string and passed the verification.
I also tried this code and it is also not working:
- (BOOL) isAlphaNumeric: (NSString *) text
{
NSCharacterSet *unwantedCharacters =
[[NSCharacterSet alphanumericCharacterSet] invertedSet];
return ([text rangeOfCharacterFromSet:unwantedCharacters].location == NSNotFound) ? YES : NO;
}
I am not sure where I am doing wrong. Do I need to encode the input text somehow before I do the check?
Currently I get the string directly from iOS6's - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text's last replacementText parameter.
Thanks!
The problem is that alphanumericCharacterSet also seems to contain the chinese letters, so the result is "correct". Apple doesn't document it this way but I've seen a few postings (e.g. from GNUStep) that seem to indicate it. (Also note that Apple does document that this set contains characters that you might not want: Informally, this set is the set of all characters used as basic units of alphabets, syllabaries, ideographs, and digits.).
A simple yet inelegant workaround is to define the character set yourself, if all you want is the english alphabet without any foreign letters like Ü or ß:
NSCharacterSet *alphaSet = [NSCharacterSet characterSetWithCharactersInString:#"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890"];
When you're targeting iOS >= 7, one of the URL*AllowedCharacterSet might be of interest. See the NSCharacterSet documentation for details.

Text character location changed when UITextView has Under line text in iOS 6

In my app i am giving command to user to create Bold,Italic and UnderLine text.
Bold and Italic text is coming perfectly.
and also Underline text working Perfectly in iOS 7.
But When used that code in iOS 6 the Underline will come under the text but the next character will come on range.location=0.
I just want the text go smoothly with UnderLine Text when User type.
My code for UnderLine Text is
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"shouldChangeTextInRange %d - %d - %d",range.location,range.length,txtViewOfNotes.attributedText.length);
if (range.location==0) {
NSLog(#"location 0");
}
else{
NSLog(#"location 123");
NSMutableAttributedString *mat = [txtViewOfNotes.attributedText mutableCopy];
[mat addAttributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle)} range:NSMakeRange (mat.length-1, 1)];
txtViewOfNotes.attributedText = mat;
}
}
OutPut for Example:
e
n
i
l
I am typing now txtUnder
Any one know why this is happening in only iOS 6.
You should just update the [textView textStorage] attributes rather than making a copy of the attributed string and replacing it.
So get rid of the mutableCopy line of code and replace the next line with:
[[textView textStorage] addAttribute:...]
Your code is completely replacing the textView's attributed string and as a consequence the cursor position is being reset. No need to replace it, just add attributes to the existing textStorage (which is already a mutableAttributedString).
See here for more on formatting text and images in UITextView and NSTextView.

iOS: sizeWithFont for single character is different than in a string?

I am trying to determine the precise position of a character in a UILabel, say:
(UILabel *)label.text = #"Hello!";
I'd like to determine the position of the 'o'. I thought that I could just sum the widths of all the preceding characters (or the whole preceding string) using sizeWithFont. The width value I get though is bigger by about 10% than what it should be. Summing the widths of individual letters (i.e. [#"H" sizeWithFont...] + [#"e" sizeWithFont...] + l... + l...) accumulates more error than [#"Hell" sizeWithFont...].
Is there a way of accurately determining the position of a single glyph in a string?
Many thanks.
Yes, but not in a UILabel and not using sizeWithFont:.
I recently worked with Apple Developer Support, and apparently sizeWithFont: is actually an approximation. It becomes less accurate when your text (1) wraps across multiple lines and (2) contains non-latin characters (i.e. Chinese, Arabic), both of which cause line spacing changes not captured by sizeWithFont:. So, don't rely on this method if you want 100% accuracy.
Here are two things you can do:
(1) Instead of UILabel, use a non-editable UITextView. This will support the UITextInput protocol method firstRectForRange:, which you can use to get the rect of the character you need. You could use a method like this one:
- (CGRect)rectOfCharacterAtIndex:(NSUInteger)characterIndex inTextView:(UITextView *)textView
{
// set the beginning position to the index of the character
UITextPosition *beginningPosition = [textView positionFromPosition:textView.beginningOfDocument offset:characterIndex];
// set the end position to the index of the character plus 1
UITextPosition *endPosition = [textView positionFromPosition:beginningPosition offset:1];
// get the text range between these two positions
UITextRange *characterTextRange = [textView textRangeFromPosition:beginningPosition toPosition:endPosition]];
// get the rect of the character
CGRect rectOfCharacter = [textView firstRectForRange:characterTextRange];
// return the rect, converted from the text input view (unless you want it to be relative the text input view)
return [textView convertRect:rectOfCharacter fromView:textView.textInputView];
}
To use it, (assuming you have a UITextView called myTextView already on the screen), you would do this:
myTextView.text = #"Hello!";
CGRect rectOfOCharacter = [self rectOfCharacterAtIndex:4 inTextView:myTextView];
// do whatever you need with rectOfOCharacter
Only use this method for determining the rect for ONE character. The reason for this is that in the event of a line break, firstRectForRange: only returns the rect on the first line, before the break.
Also, consider adding the method above as a UITextView category if you're gong to be using it a lot. Don't forget to add error handling!
You can learn more about how firstRectForRange: works "under the hood" by reading the Text, Web, and Editing Programming Guide for iOS.
(2) Create your own UILabel by subclassing UIView and using Core Text to render the strings. Since you're doing the rendering, you'll be able to get the positions of characters. This approach is a lot of work, and only worthwhile if you really need it (I, of course, don't know the other needs of your app). If you aren't sure how this would work, I suggest using the first approach.
Well fonts are smart now a day and take in respect the position of a character to its pervious character.
Here is an example on how the starting position of the letter o:
NSRange posRange = [hello rangeOfString:#"o"];
NSString *substring = [hello substringToIndex:posRange.location];
CGSize size = [substring sizeWithFont:[UIFont systemFontOfSize:14.0f]];
No you can do the same for the string including the letter o and substract the size found in the string without the letter o.
THis should give the an nice start position of the letter and the size.
in ios6 you can do using attributed string
NSMutableAttributedString *titleText2 = [[NSMutableAttributedString alloc] initWithString:strHello];
NSRange posRange = [hello rangeOfString:#"o"];
[titleText2 addAttributes:[NSDictionary dictionaryWithObject:[UIFont systemFontOfSize:14.0f] forKey:NSFontAttributeName] range:NameRange];
and set your textView with this attributed string

Resources