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];
}
}
Related
IM having an issue with changing the return keys type while still editing the textfield of my view. So when the user clicks the textfield i have a few checks that change the return type of the keyboard, these checks are placed in - (void)textFieldDidBeginEditing:(UITextField *)textField, when i change the keyboards return key here the code works fine. Im just changing the keyboards retrun key like so [textField setReturnKeyType:UIReturnKeyDone];. So there are 2 textfields username and password. If theres text in both the textfields i want to change the return key to DONE if theres text in only one of the text fields i want to change it to NEXT so i can jump back and forth between the textfields.So now im placing some checks and balances in - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string. Yet the same code im placing in textFieldDidBeginEditing is not working in this function. Ive read a bunch of posts and they all say to remove the text field as the first responder then set the return key and become the responder again, but this messes up my current flow in the respective methods. I also read that i have to call [textfield reloadInputFields] after setting the return key, yet again this does not work. You would think that apple would have fixed a bug like this by now. Anyway does anyone have some input here?
I had to implement an add tag logic that required to change the keyboard return key depending on the text typed into the UITextField. Finding how to change the return key was quite easy, but when I started testing, I noticed that this solution only works for iOS10, but not for iOS9. After spending some time and doing some research, I came up with this workaround, it's not the nicest but at least it works.
if #available(iOS 10.0, *) {
textField.reloadInputViews()
} else {
textField.keyboardType = .numberPad
textField.reloadInputViews()
textField.keyboardType = .default
textField.reloadInputViews()
}
Try it out and Let me know
I have made demo for your question and its running perfect as per your need or you can modify it as per
// This is the Editing Changed Action Event of Both textField Created From StoryBoard
- (IBAction)txtEditingChanged:(UITextField *)sender
{
[sender resignFirstResponder];
[sender becomeFirstResponder];
}
// This is the Editing Did End Action Event of Both textField Created From StoryBoard
- (IBAction)txtEditingEnd:(UITextField *)sender
{
if (txtUserName.text.length == 0 || txtPassword.text.length == 0)
{
[txtUserName setReturnKeyType:UIReturnKeyNext];
[txtPassword setReturnKeyType:UIReturnKeyNext];
}
else
{
[txtUserName setReturnKeyType:UIReturnKeyDone];
[txtPassword setReturnKeyType:UIReturnKeyDone];
}
}
// This is Next And Done Button Events i.e. UITextField Delegate
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == txtUserName && textField.returnKeyType == UIReturnKeyNext && textField.text.length != 0)
{
[txtPassword becomeFirstResponder];
}
else if (textField == txtPassword && textField.returnKeyType == UIReturnKeyNext && textField.text.length != 0)
{
[txtUserName becomeFirstResponder];
}
else
{
// This is your Done Button Event You Can Procced Here
}
return YES;
}
While trying to allow multi token deletions, as user holds the backspace key in VENTokenField to act the same as the native email app, or messages app, I have come across many problems...
First, I can only detect one tap on the backspace key from the initial code the VENToken's UITextField subclass offer (which is technically touching private API) - (BOOL)keyboardInputShouldDelete:(UITextField *)textField. That is fine, but not helpful for detecting long press on backspace button, which only works while you actually have characters in a certain UITextField, and not while the UITextField is empty such as in our case.
I have also came across this blogpost which suggest another approach of accessing more of the private API, however, does not offer solution to my problem. As it's not documented, I was wondering if there is a valid way to detect this event at all?
I've resolved it by first, comment out anything that was in VENBackspaceTextField class'
keyboardInputShouldDelete:(UITextField *)textField
Then, added 2 consts in VENTokenField header:
NSString * const kTextEmpty = #"\u200B"; // Zero-Width Space
NSString * const kTextHidden = #"\u200D"; // Zero-Width Joiner
Everytime the token becomes first responder, make sure the textField has the empty text:
- (void)inputTextFieldBecomeFirstResponder {
[self.inputTextField becomeFirstResponder];
if (self.tokens.count) {
[self.inputTextField setText:kTextEmpty];
}
...
}
And set it to hidden when cursor is not visible:
- (void)setCursorVisibility {
NSArray *highlightedTokens = [self.tokens filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(VENToken *evaluatedObject, NSDictionary *bindings) {
return evaluatedObject.highlighted;
}]];
BOOL visible = [highlightedTokens count] == 0;
if (visible) {
[self inputTextFieldBecomeFirstResponder];
} else {
[self.invisibleTextField becomeFirstResponder];
[self.invisibleTextField setText:kTextHidden];
}
}
Then, modified the textField Delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (self.tokens.count && [string isEqualToString:#""] && [textField.text isEqualToString:kTextEmpty]){
VENToken *lastToken = [self.tokens lastObject];
lastToken.highlighted = YES;
[_inputTextField setText:kTextHidden];
_inputTextField.alpha = 0.0;
return NO;
}
if ([textField.text isEqualToString:kTextHidden]){
[self deleteHighlighted];
[self unhighlightAllTokens];
return (![string isEqualToString:#""]);
}
//If there are any highlighted tokens, delete
[self deleteHighlighted];
return YES;
}
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
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Moving the cursor to the beginning of UITextField
Hello i have a textview with text I want to move cursor position at beginning I have use NSMakeRange but i don't know why its not working. I have written NSMakeRange is different places , hoping that it would run atleast once but didn't work. Here is the code. thx in advance
- (void)viewDidLoad
{
[super viewDidLoad];
apnatxtView.textColor=[UIColor lightGrayColor];
apnatxtView.text=#"Description goes here";
totalLenght=apnatxtView.text.length;
apnatxtView.selectedRange=NSMakeRange(0,0);
}
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
apnatxtView.selectedRange=NSMakeRange(0,0);
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[apnatxtView resignFirstResponder];
}
- (void)textViewDidChange:(UITextView *)textView{
if (apnatxtView.text.length == 0) {
apnatxtView.textColor= [UIColor lightGrayColor];
apnatxtView.text=#"Description goes here";
apnatxtView.selectedRange=NSMakeRange(0, 0);
}
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (apnatxtView.textColor == [UIColor lightGrayColor]) {
apnatxtView.textColor=[UIColor blackColor];
// apnatxtView.text=#"Description goes here";
apnatxtView.text=nil;
return YES;
}
}
This works in my testing on the iOS 6.0 simulator:
- (void)textViewDidBeginEditing:(UITextView *)textView {
dispatch_async(dispatch_get_main_queue(), ^{
textView.selectedRange = NSMakeRange(0, 0);
});
}
I guess it updates the selection based on the touch location after it sends the textViewDidBeginEditing: message. The dispatch_async works around that.
K i found the solution. Im setting the cursor position before cursor appears I cut and paste the code in KeyBoardDidShow notification and it worked pretty fine.