I have a UITableView to which i've assigned a UITextField to each cell. I want to be able to accept input from each text field and dismiss the keyboard when the user taps anywhere on the screen other than the keyboard. This is the code I have so far, but I find the keyboard only gets dismissed when im on the last cell in the table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.gradesTableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
self.tf = [[UITextField alloc] initWithFrame:CGRectMake(225, (cell.contentView.bounds.size.height-30)/2, 50, 30)];
[self.tf setDelegate: self];
self.tf.tag = indexPath.row;
self.tf.textAlignment = NSTextAlignmentCenter;
self.tf.placeholder = #"0";
self.tf.backgroundColor = [UIColor grayColor];
self.tf.borderStyle = UITextBorderStyleRoundedRect;
self.tf.keyboardType = UIKeyboardTypeDecimalPad;
[cell addSubview:self.tf];
cell.textLabel.text = [self.adderArrayLabels objectAtIndex:indexPath.section];
return cell;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
self.tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap)];
[self.view addGestureRecognizer:self.tapGR];
NSLog(#"Started editing");
}
Ive tried both endEditing: and resignFirstResponder but both only dismiss the keyboard when im on the textfield in the last cell.
- (void)tap {
[self.tf endEditing:YES];
//[self.tf resignFirstResponder];
NSLog(#"tap called");
self.tapGR.enabled = NO;
}
With the NSLog statements in the code I can confirm the method tap is called every time the appropriate tap gesture is recognized but still the keyboard stays. How do I fix this?
The problem is here:
self.tf
Your class has a text field property, and every time you create a new text field, you assign it to this property. Then, you only try to endEditing: or resignFirstResponder on this property, which will always be the text field on the cell most recently created.
You don't need this property at all and can just use a local text field variable when creating the cells.
Then change your tap method to this:
- (void)tap {
[self.view endEditing:YES];
NSLog(#"tap called");
self.tapGR.enabled = NO;
}
And truly, the method should probably be: - (void)tap:(id)sender;
Also, as I commented, the gesture recognizer should be added in viewDidLoad. We only need to add it once, not each and every time a text field begins editing. The only reason to add it every time a text field begins editing is if you're also removing it every time the text field ends editing... but as the method that the gesture calls simply gets rid of the keyboard, I see no reason to do that.
Related
I have implemented UITableView where each cell contains some buttons
In order to detect if user taps on table I have added UITapGestureRecognizer.
I want the buttons in the cells to do nothing when user taps on them.
I have implemented this selector:
- (void) backgroundTouched:(UITapGestureRecognizer*)sender {
UIView *view = sender.view;
NSLog(#"backgroundTouched %#", view);
}
I see that when I tap anywhere on the table this selector gets called except if I tap on any of the buttons contained in the UITableViewCell.
How can I avoid that?
Here is the code which creates the UITapGestureRecognizer:
pragma mark UISearchControllerDelegate
- (void)didPresentSearchController:(UISearchController *)searchController
{
NSLog(#"didPresentSearchController");
self.cancelGesture = [UITapGestureRecognizer new];
[self.cancelGesture addTarget:self action:#selector(backgroundTouched:)];
self.cancelGesture.cancelsTouchesInView = YES;
[self.tableView addGestureRecognizer:self.cancelGesture];
}
If you don't want your buttons to do anything, disable the userInteractionEnabled of the button.
cell.addCashButton.userInteractionEnabled = NO;
My suggestion:
Table has own touch action facility use it's delegate method didSelectRowAtIndexPath
And if you are using UIButton in custom cell then instead of UITapGestureRecognizer you can add button action method in cellForRowAtIndexPath with button's tag like below
in cellForRowAtIndexPath method
cell.yourButton.tag = indexPath.row
[cell.yourButton addTarget:self action:#selector(myButtonActionMethod:) forControlEvents:UIControlEventTouchUpInside]
And declare button action method
-(void) myButtonActionMethod:(UIButton*)sender
{
NSLog(#"you clicked on button %#", sender.tag);
}
I am working on a app using TableView now i am facing an issue listed below.
Inside my TableView there is UITextView on it, that MUST be selectable, but not editable (because I need to use and proceed links).
My issue is:
when I tap on a link as everybody does, it doesn't work. I need to hold it a bit longer to make it work. I thought that it is because of "Selectable" property brings in a Double Tap Gesture recognizer, so my textView checks if there is a second tap, but I don't know how to find and remove only double tap recognizer.
What should I do?
Thank you.
Have you considered replacing the TextView with a UIWebView, and just do a loadHTMLString function?
This way when you tap on a link, it will open instantly? You can even have a UIWebView delegate and do what you want when the link is pressed(Custom UIWebView instead of auto opening in safari etc)
You've to handle tap event.. Through this code
tapGesture.numberOfTapsRequired = 1
OR
To do this, you will need to embed one in your UITableViewCell. But there's no need to create a custom cell. Here is the basic idea of what you will want to do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextView *comment = [[UITextView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, tableView.rowHeight)];
comment.editable = NO;
comment.delegate = self;
[cell.contentView addSubview:comment];
[comment release];
}
return cell;
}
You will, of course, need to set your rowHeight if you don't want the standard 44pt height that comes with the cell. And if you want actual cells, you'll need to add your own logic so that only the cell you want is a textView, but this is the basic idea. The rest is yours to customize to your fitting. Hope this helps
EDIT: to bypass the textView to get to your cell, there are two ways to go about this.
1) you can make a custom textView class and overwrite touchesBegan to send the message to super:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
this will send the touch events to its superview, which would be your tableView. Considering you didn't want to make custom UITableViewCells, I imagine you probably don't want to make a custom textView class either. Which leads me to option two.
2) when creating the textView, remove comment.editable = NO;. We need to keep it editable, but will fix that in a delegate method.
In your code, you will want to insert a textView delegate method and we'll do all our work from there:
EDIT: changing this code to use with a UITableViewController
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
// this method is called every time you touch in the textView, provided it's editable;
NSIndexPath *indexPath = [self.tableView indexPathForCell:textView.superview.superview];
// i know that looks a bit obscure, but calling superview the first time finds the contentView of your cell;
// calling it the second time returns the cell it's held in, which we can retrieve an index path from;
// this is the edited part;
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
// this programmatically selects the cell you've called behind the textView;
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
// this selects the cell under the textView;
return NO; // specifies you don't want to edit the textView;
}
If that's not what you wanted, just let me know and we'll get you sorted out
Finding and Removing Double Tap Gesture recognizer
Objective C
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])
{
[(UITapGestureRecognizer *)gestureRecognizer setNumberOfTapsRequired:1];
gestureRecognizer.enabled = NO;
}
}
Swift
func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer)
{
if gestureRecognizer.isKindOfClass(UITapGestureRecognizer)
{
(gestureRecognizer as! UITapGestureRecognizer).numberOfTapsRequired = 1
gestureRecognizer.enabled = false
}
}
How to get data in UITableview instead of tapping on keyboard UITextfield. In UITableview, how to do multiple selection of data.
Edited:- I have a UITextfield. On tapping it, tableview should pop up with data in it instead of keyboard. When a row of tableview is selected, then checkmark should appear and that data should be seen in UITextfield.
Answer of your first question -
Your keyboard will hide by using this code.
-(BOOL)textField:(UITextField *)textField shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]) {
[textField resignFirstResponder];
return NO;
}
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
[self.view endEditing:YES];
// load your tableView here.
// Everything must be custom.that is your table view is just like a popup.
}
Answer of your second question -
Now current scenario is your table view is shown on screen.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *selectedValue = [yourArray objectAtIndex:indexPath.row];
yourTextView.text = selectedValue;
yourTableView.hide = YES;
}
Here after selecting any row that value is shown in yourTextView.but after that you have to hide that tableView. Try this.May this will help you.
-(void)textViewDidBeginEditing:(UITextView *)textView
{
[self.view endEditing:YES]; // this will make key board hide
yourTableView.hide = NO; // here show tableview make sure tableview allocated out side and here you will be just showing.
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
yourTextView.text = yourArray[indexPath.row];
yourTableView.hide = YES;
}
Use UITextField.inputView property.
More on the subject here:
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/InputViews/InputViews.html
I currently have a table with 8 rows that each have a label on the right side and a button on the left. I was hoping that I could have all the buttons hidden until the user presses an "edit" button in the top right corner and then they would appear allowing the user to interact with each table cell. I don't know if this is possible, because they are in UITableViewCells or if there is an easier method to summoning a button for each cell
UPDATE
okay so I have placed in all the hidden properties and there seem to be no errors, but the app doesn't recognize any of it. The buttons remains unhidden despite the fact that they are set to be initially hidden. Here is my code
Here is my Table Cell code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"BlockCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = #"Free Block";
UIButton*BlockButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
BlockButton.frame = CGRectMake(225.0f, 5.0f, 75.0f, 35.0f);
[BlockButton setTitle:#"Change" forState:UIControlStateNormal];
[BlockButton addTarget:self action:#selector(Switch:) forControlEvents:UIControlEventTouchUpInside];
Blockbutton.backgroundColor = [UIColor colorWithRed:102/255.f
green:0/255.f
blue:51/255.f
alpha:255/255.f];
Blockbutton.hidden = YES;
[cell addSubview:BlockButton];
return cell;
}
and here is my method code:
- (IBAction)Editmode:(UIButton *)sender
{
Blockbutton.hidden = !Blockbutton.hidden;
[self.tableView reloadData];
}
any thoughts or ideas as to what might be the issue?
You'll need to create a UITableViewCell subclass if you don't already have one. In that class, override setEditing:animated: and if the new value is YES, then enable/add/unhide the button.
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (editing) {
// add your button
someButton.hidden = NO;
} else {
// remove your button
someButton.hidden = YES;
}
}
It would be optional, but you are encouraged to animate the change if animated is YES.
Note: this assumes you have the edit button already hooked up the change the editing mode of the UITableView. If you don't, call setEditing:animated: on the UITableView in the button action. This will automatically call setEditing:animated: on each visible table cell.
The trick here is to keep in mind that a table's cells are determined by cellForRowAtIndexPath:. You can cause that method to be called all over again by sending the table reloadData:.
So, just keep a BOOL instance variable / property. Use the button to toggle that instance variable and to call reloadData:. If, at the time cellForRowAtIndexPath: is called, the instance variable is YES, set the button's hidden to YES; if NO, to NO.
take a BOOL variable which defines the whether to show delete button or not, use this BOOL var to for btnName.hidden = boolVar, initially make boolVar = NO, when user taps on edit toggle bool var and reload the tableview.
Another option is to test if you are in edit mode in the cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = //(obtain your cell however you like)
UIButton *button = cell.button; //(get button from cell using a property, a tag, etc.)
BOOL isEditing = self.editing //(obtain the state however you like)
button.hidden = !isEditing;
return cell;
}
And whenever you enter editing mode, reload tableView data. This will make the table view ask for the cells again, but in this case the buttons will be set not to hide.
- (void)enterEditingMode {
self.editing = YES;
[self.tableView reloadData];
}
I have a UITableView which I want to work in a similar way to the Contacts app in that there's an edit button which when clicked transforms the cells into edit cells.
At the moment they are set up using the cell style 'left detail' and I have overridden the setEditing method ready for implementation but I don't know how to transform the cells.
Some other answers on here included "Monitor when the table view's editing property changes (when the Edit button is pressed). Then add code to your delegate methods to compose, draw and indent cells in a different way, when the table view is in editing mode." which is exactly what I want but don't know how to do.
- (void)setEditing:(BOOL)flag animated:(BOOL)animated
{
[super setEditing:flag animated:NO];
if (flag == YES){
// Change views to edit mode.
self.textField = [[UITextField alloc] initWithFrame:[_titleLabel frame]];
[self.textField setText:_titleLabel.text];
[self.view addSubview:self.textField];
}
else {
// Save the changes if needed and change the views to noneditable.
[_titleLabel setText:self.textField.text];
[self.textField removeFromSuperview];
}
}
In my method I have code taken from another question which works.. sort of (it makes a new editable text field on the fly in the wrong place and doesn't hide the label).
The apple guidelines aren't specific enough for me to understand how to develop the views.
In a nutshell, the way this works is you set an edit flag on the entire UITableView and then you implement a couple of methods (canEditRowAtIndexPath,commitEditingStyle) declared in the UITableViewDataSource protocol that determine which cells are being edited.
So first you need to put the UITableVIew into edit mode. You want to do that in the handler for your toolbar button:
[self.tableView setIsEditing:YES animated:NO];
Then, the tableview will call canEditRowAtIndexPath to determine if the row can be edited :
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
Finally, when the user is done editing, this method gets called:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html
There is another example here:
http://www.behindtechlines.com/2012/06/02/enabling-configuring-uitableview-edit-mode/
I have a workaround.
If I create a custom row and make it look the same as the 'left detail' style, but using a textview on the right instead of a label, I can change the 'seteditable' and 'setenabled' fields of the views so that on edit they allow editing. I have hacked the font color so it changes when edit is clicked so the user can see that it is now editable.
This seems very messy - so I'm still looking for the best way to do this.
- (void)setEditing:(BOOL)flag animated:(BOOL)animated
{
[super setEditing:flag animated:NO];
if (flag == YES){
[self.tableView setEditing:YES animated:NO];
[self.sampleLabel setEnabled:YES];
[self.sampleLabel setTextColor:[UIColor blackColor]];
}
else {
[self.sampleLabel setEnabled:NO];
[self.sampleLabel setTextColor:[UIColor darkGrayColor]];
}
}
- (void)configureView
{
self.titleLabel.text = [[self.detailItem valueForKey:#"title"] description];
self.ticketNumberLabel.text = [[self.detailItem valueForKey:#"reference"] description];
self.detailsLabel .text = [[self.detailItem valueForKey:#"details"] description];
self.sampleLabel.text = [[self.detailItem valueForKey:#"reference"] description];
// initially set labels to not be editable
[self.detailsLabel setEditable:NO];
[self.sampleLabel setEnabled:NO];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
// item can't be deleted now
return NO;
}