This is my First question on ios
I am using two UITextView objects (textView1 and textView2) in a View, Each of them has some character limit with some following Scenario:
Initially user can only enter into textView1.
When the entered character limit of textView1 is over, the cursor will automatically shift to textView2.
After building the project, If user tap the textView2 and try to write into it, Cursor must shifted to textView1 (because it is empty).
I wrote the code and everything works fine except the third scenario, User can only enter into textView1 but focus is still on textView2
Steps to reproduce:
Build the project
user tap the textView2 first and try to write something.
According to written code, Focus remain in textView2 but user are writing into textView1 (see the attachment)
Here is the snapshot:
Here is the written code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.textView1 becomeFirstResponder];
}
- (void)textViewDidChange:(UITextView *)textView{
NSInteger restrictedLengthForTextView1 = 110;
NSInteger restrictedLengthForTextView2 = 130;
NSString *temp=textView.text;
if(textView == self.textView1){
if([[textView text] length] > restrictedLengthForTextView1){
textView.text=[temp substringToIndex:[temp length]-1];
[textView resignFirstResponder];
[self.textView2 becomeFirstResponder];
}
}else{
if([[textView text] length] > restrictedLengthForTextView2){
textView.text=[temp substringToIndex:[temp length]-1];
[self.textView2 resignFirstResponder];
}
}}
- void()textViewDidBeginEditing:(UITextView *)textView{
NSInteger restrictedLengthForTextView1 = 110;
NSLog(#"dalknwdlakwd");
if([[self.textView1 text] length] < restrictedLengthForTextView1){
if(textView == self.textView2){
[self.textView2 resignFirstResponder];
[self.textView1 becomeFirstResponder];
}
}}
Please help me here..
please do as per following:
in .h file
#interface ViewController : UIViewController<UITextViewDelegate>
{
IBOutlet UITextView *txtView1;
IBOutlet UITextView *txtView2;
}
#end
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[txtView1 becomeFirstResponder];
txtView2.editable=NO;
}
implement the textView delegate method like below:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if(textView.tag==1)
{
if([textView.text length]>25)
{
txtView2.editable=YES;
[txtView2 becomeFirstResponder];
}
}
return YES;
}
i have taken text length limit in first textview as 24 characters as an example.
i hope this will help you.
It is a known bug, with resigning and becoming first responder within the same runloop. Try the following
[textView2 resignFirstResponder];
[textView1 performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
An update to Annadurai's answer: it's still a bug in 2016! After trying others' suggestions to deselect the surrounding tableview cell, and/or change the tint color only this answer worked for me:
[textView1 performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
FYI My case was that I was resigning a textView, reloading the table, and returning to the same textView. Before this fix - no cursor on the reloaded textView (Yes I could type and see characters.) After the performSelector... afterDelay - the cursor was visible again.
Related
I can see how to set the keyboard's overall type via:
self.myTextView.keyboardType = UIKeyboardTypeDefault;
How can I toggle the default keyboard's mode from ABC to 123 and back again via code? Basically the moment the user taps the # character (the # symbol is available when they're in 123 mode) I want to switch their keyboard back to ABC mode.
Any ideas?
You might be able to accomplish this in by using the UITextViewDelegate. It allows you to intercept the keys as they are pressed in the UITextView. This will allow you to switch keyboards when the user presses a certain key. In order to revert back to the default state of the UIKeyboardTypeDefault keyboard, you'll need to change the keyboard type to another, then back to the default.
In your ViewController.h file, make it implement the UITextViewDelegate protocol:
#interface ViewController : UIViewController <UITextViewDelegate>
In your ViewController's viewDidLoad method in the ViewController.m, set the textField's delegate to the view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myTextView.delegate = self;
}
Finally, we need to capture the key as it is being entered and change the keyboard appropriately. We do this in the shouldChangeCharactersInRange: method.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if( [#"#" isEqualToString:text] )
{
NSLog( #"Toggling keyboard type");
textView.inputView = nil;
[textView resignFirstResponder];
[textView setKeyboardType:UIKeyboardTypeEmailAddress];
[textView becomeFirstResponder];
[textView reloadInputViews];
textView.inputView = nil;
[textView resignFirstResponder];
[textView setKeyboardType:UIKeyboardTypeDefault];
[textView becomeFirstResponder];
[textView reloadInputViews];
}
return YES;
}
So I was originally confused and thought you actually wanted to change the keyboard type. Now that I'm reading your comment, I realize that you're actually wanting to reset the keyboard to it's default state of showing the letters, instead of numbers and special characters. The above code now does that.
The premise of my app is simple. The user enters in some information into textFields and textViews and when saved, the TableView is populated with that information (with a combination of Core Data and NSFetchedResultsController).
In version 1 of my app, the "add entry" screen has only UITextFields and no UITextViews. In version 1.1 of my App, I have brought a UITextView for notes. The default text is "Additional Notes: " and this is set in the Storyboard.
Problem
What I'm seeing is, if I create an entry in version 1 and then update my app to version 1.1 from Xcode, the existing entries, when you click on them in the UITableView do not display the word "Additional Notes :" in the UITextView until I actually click on the UITextView cell in which case, my shouldBegin method gets called and it displays it. That is undesirable though because users who upgrade should see the word "Additional Notes: " in the UITextView for existing entries. Essentially Additional Notes is a "placeholder" so if you don't enter in any notes, you should always see those words.
I've set the text in the UITextView in Storyboard but nothing seems to be working.
I have two different view controllers for creating a new entry and editing an entry in Storyboard (because of some slight adjustments) and if you add a new entry, it shows the word Additional Notes :". If you add a new entry but didn't put in any notes, when you edit it, you'll still see the word Additional Notes:. However, entries added from version 1 of the app do not show the word "Additional Notes: " when it comes to editing the entry and I cannot understand why this is the case.
Here are my two main methods:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if([[textView text] isEqualToString:#"Additional Notes: "]){
[textView setText:#"Additional Notes:\n"];
}
return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
if([[[textView text] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString:#""]){
[textView setText:#"Additional Notes: "];
}
return YES;
}
So I know I'm missing something, but why can't users who have upgraded, have existing entries displaying the word Additional Notes: in the UITextView without having to click on it.
Any guidance would really be appreciated.
just replace the txt message text in your textview text name,
-(void)viewWillAppear:(BOOL)animated
{
[txtmessage setText:#"Additional Notes:"];
[txtmessage setTextColor:[UIColor lightGrayColor]];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"])
{
[textView resignFirstResponder];
if(txtmessage.text.length == 0){
txtmessage.textColor = [UIColor lightGrayColor];
txtmessage.text = #"Additional Notes:";
[txtmessage resignFirstResponder];
}
return NO;
}
if(textView.text.length >=65)
{
[textView resignFirstResponder];
return NO;
}
if([text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location == NSNotFound) {
return YES;
}
[textView resignFirstResponder];
return NO;
return YES;
}
- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
if (txtmessage.textColor == [UIColor lightGrayColor]) {
txtmessage.text = #"";
txtmessage.textColor = [UIColor blackColor];
}
return YES;
}
-(void) textViewDidChange:(UITextView *)textView
{
if(txtmessage.text.length == 0){
txtmessage.textColor = [UIColor lightGrayColor];
txtmessage.text = #"Additional Notes:";
[txtmessage resignFirstResponder];
}
}
I'm trying to move my first responder on using tags in a tableview cell. I've set _txtFieldActive to pick up the active UITextFields tag. I can see this when I press the next button on the keyboard via NSLog. Now however I can't seem to figure out how to resignfirstresponder on that tag, and then move my first responder onto tag 102?? I get an error on the line of code trying to assign tag 102 to *tmp.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
switch (textField.tag)
{
case 101:
//Do Nothing do not want to close keyboard but move on to next UITextField
if (_txtFieldActive.tag == 101)
{NSLog(#"Tag = 101");
UITextField *tmp = [textField.tag == 102];
[tmp becomeFirstResponder];
}
break;
case 102:
[textField resignFirstResponder];
}
return YES;
}
Many thanks all for your help in advance for any pointers.
Jon.
To get a reference to a view in the current view's hierarchy with a given tag, we need to call viewWithTag:.
if (_txtFieldActive.tag == 101) {
NSLog(#"Tag = 101");
UITextField *tmp = [self.view viewWithTag:102];
[tmp becomeFirstResponder];
}
Try that on for size.
If this is a UITableViewController subclass rather than a UIViewController subclass, you might need [self.tableView viewWithTag:102];, but self.view should work in either case.
Thanks in advance for your help. I try to boost my learning curve of Objective-c and defy myself with a lot of cases.
I try to do a simple app which simulates the comportment of a terminal session:
First step: a prompt is waiting and I enter a first command: eg. date. Then I get a result. Second: a prompt is waiting again below the result. Then I give a second command: time
etc.
I did a lot of tests with an UItextField to input different texts and commands, and a UITextView to display the results. I also use an NSMutable Array to stock all inputs/results. Nothing work very well. I would like to get your advice on that matter and that you point me the best approach or a code source to learn to reproduce a terminal gui. Is an array a good solution, how to place the textField at the end of the textView, etc.? Thanks+
This is just a general approach of what you want to achieve.
Use a single UITextView for input and output.
At first, add a simple character to your UITextView, for example ">", so the user starts typing after this character.
Implement this UITextView delegate method to listen on when the user taps "return" :
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]) {
// Handle what happens when user presses return
return NO;
}
return YES;
}
What I would do here is when the user presses return, get the whole UITextField's content, and use something like NSArray *stringArray = [_textField.text componentsSeparatedByString: #">"];. That way, the last element of your array is the last command the user entered. Then, test the command and append the appropriate answer to the UITextView. Don't forget to add #"\n>" after it so you prompt the user a new command line.
What's left to do here is prevent the user from erasing your ">".
It's an idea, there's probably many other ways to do it. Comment if you need more details on something !
SPOILER ALERT : full code
In my storyboard, I simply have a UITextView linked to ViewController.h, with the name textView. Note that the following code does not handle the user removing text from the UITextView. You can test the code by typing "hello" in the console.
ViewController.m :
#import "ViewController.h"
#interface ViewController () {
// Store supported commands and outputs
NSDictionary *commands;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize textView
_textView.text = #">";
[_textView becomeFirstResponder];
// Init supported commands with associated output
commands = [NSDictionary dictionaryWithObjectsAndKeys:#"Hello World !", #"hello", nil];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// Deleting something
if([text isEqualToString:#""]) {
UITextPosition *beginning = textView.beginningOfDocument;
UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
UITextPosition *end = [textView positionFromPosition:start offset:range.length];
UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
NSString *textToReplace = [textView textInRange:textRange];
NSLog(#"%#", textToReplace);
if ([textToReplace isEqualToString:#">"]) return NO;
return YES;
}
if([text isEqualToString:#"\n"]) {
// Handle what happens when user presses return
NSArray *stringArray = [_textView.text componentsSeparatedByString: #">"];
NSLog(#"Last command : %#", [stringArray lastObject]);
[self handleCommand:[stringArray lastObject]];
return NO;
}
return YES;
}
-(void)handleCommand:(NSString*)command {
NSString *output = [commands objectForKey:command];
// If an unsupported command was typed
if (output == nil) {
output = #"Unknown command";
}
// Write output to the textView
_textView.text = [_textView.text stringByAppendingString:#"\n"];
_textView.text = [_textView.text stringByAppendingString:output];
_textView.text = [_textView.text stringByAppendingString:#"\n>"];
}
This is the textView's content from the simulator :
>hello
Hello World !
>yes
Unknown command
>
Unknown command
>hello
Hello World !
Many ways to do this. If I were doing it I think I would do the following:
A dictionary to hold the input and output for each command
Very large UITextView with all entries in the dictionary outputted in the format you like
A no border UITextField to act as the prompt.
You would have to write the following:
A method to place the UITextFiled at the right line of the UITextField
A method to populate the Diciotnary
A method to populate the UITextField from the dictionary
In my app i have UITextField on view of VC1(UIViewController). When i change text in textfield i call pushing of another controller VC2 with UISearchBar on its view. After pushing im assigning UISearchBar text to the textfield text from VC1.
On xib my textfield already have some text "Test string".
When I'm append VC1 textfield with any char - VC2 pushing and text on searchbar is normal.
But when I'm press backspace key on iPhone keyboard - VC2 pushed and text on searchfield start deleting char by char, while whole string not been empted. It happend because delegate method calls recursively.
How to fix that behaviour of UISearchBar? I mush to have searchbar active with keyboard opened when VC2 appears! It's main condition. Sure, if i'll remove [self.searchBar becomeFirstResponder] all will works fine.
Some code here:
#implementation ViewController1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString * resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
ViewController2 * vc2 = [ViewController2 new];
[self.navigationController pushViewController:vc2 animated:YES];
[vc2 loadText: resultString];
return NO;
}
#end
#implementation ViewController2
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.searchBar becomeFirstResponder];
}
- (void) loadText: (NSString *) text
{
self.searchBar.text = text;
}
#end
Sample source code of the problem: http://yadi.sk/d/NJmTLot73_vrE
I've gone through the code and for some reason the delete/backspace key is getting called repeatedly by the UIKeyboard's Accessibility function. I haven't been able to find a reason yet but one workaround is to put the [self.searchBar becomeFirstResponder]; line into viewDidAppear instead of viewWillAppear - is that an acceptable workaround? The keyboard animation is slightly different but I'm not sure how sensitive your needs are to that.
I've been experiencing strange UISearchBar animations on iOS 7. Solved the problem by putting my becomeFirstResponder call in viewDidAppear with a delay of 0.1.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.searchBar performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.1];
}
You have a recursive call in your code.
self.searchBar.text = text;
calls to
textField:shouldChangeCharactersInRange:
which in turn calls to
loadText:
What you can do is remove the delegate from the searchBar uitextfield, set the text and then return the delegate. Something like this:
- (void) loadText: (NSString *) text
{
self.searchBar.delegate = nil;
self.searchBar.text = text;
self.searchBar.delegate = vc1;
}