I am developing an app where I have a UITableView with custom cells. Custom cells contain textfield and buttons.
Requirement:
The textfield/buttons should be disabled when the table is in edit mode (The user should only be able to delete cells and not interact with the contents. The user should exit edit mode and then interact with the textfields/buttons). You can also refer "Reminders" app in iPad, the content cannot be edited in edit mode.
Problem:
The user is still able to click on textfield (keyboard is made visible), when the table is in Edit mode.
What I have done:
If user clicks any button I do nothing in my button's action method if the table is in Edit mode which is fine fro Buttons.
if ([tableView isEditing]) {
return;
}
The issue is for textfields, I am not able to remove interaction of the textfield when in Edit mode. cellForRow is not getting called when table enters into Edit mode so that I can disable the interaction.
Is there a way where I can disable the interaction while entering into Edit Mode and enable upon exit of Edit mode.
Thank you in advance. Any pointers would be appreciated.Please let me know if you require more information about the issue
You can use below delegate method of UITextField for the same:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if ([tableView isEditing]) {
return NO;
} else {
return YES;
}
}
1) Resign any edit text Field first
-(void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath{
for (UITableViewCell *cell in [tableView visibleCells]) {
for (UIView *aView in cell.contentView.subviews) {
if ([aView isKindOfClass:[UITextField class]]) {
[aView resignFirstResponder];
break;
}
}
}
}
2) Then Dont allow any textfield to edit
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if ([tableView isEditing]) {
return NO;
} else {
return YES;
}
}
Use following code to disable editing if textFields in table view
[yourTextField endEditing:YES];
Related
In an iOS apps I have a table view that has 2 rows with textfield embedded inside.
Textfield2 is a textfield with pickerview input that I set with something like this:
textField2.inputView = pickerView;
So the thing is , the textField 2 icon on the right is only an image embedded in the textfield2.rightview that caused the image to not trigger the pickerView input when tapped.
Did select table view method also wasn't triggered because I set the textfield to fully occupy the cell. Thus, after some searching I find that disabling the textField2 user interaction enabling the didSelect to be triggered.
textField2.userInteractionEnabled = false;
However, now I'm at lost on to how to trigger the input to textField2 pickerView via the didselect tableview method. I tried this line of code but that doesn't work.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2 becomeFirstResponder];
}
}
I tried to search how to trigger input manually to textField and didn't find any clue.
Thanks before ! :)
After some debugging with a clear mind, I find that
textField2.userInteractionEnabled = false;
caused the textfield not able be the responder.
So a little workaround with this flag is enable it first in order to edit the text field and disable it again after we finished editing. Something like this :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2.userInteractionEnabled = true;
[textField2 becomeFirstResponder];
}
}
- (void)donePicker {
// to enable the did select row again
[textField2.userInteractionEnabled = true;
}
I have a tableview and a view beneath it for buttons.
I want to disable the user interaction of all the subviews within the tableview, however scrolling of the tableview should not be disabled.
This is required on clicking of 'Preview' button.
The button view should not be disabled.
Suggestions welcome.
i tried the following. but this doesn't enable the scrolling nor the button interactions.
- (IBAction)btnPreviewTapped:(id)sender {
for (UIView *eachView in self.view.superview.subviews) {
if (eachView != formsContentTableView) {
eachView.userInteractionEnabled = NO;
}
}
formsContentTableView.userInteractionEnabled = YES;
self.buttonView.userInteractionEnabled = YES;
[self.btnPreview setTitle:#"Submit" forState:UIControlStateNormal];
}
I would create a property #property (nonatomic, assign) BOOL isPreview;, assign it NO as initial value self.isPreview = NO; and then in the -tableView:cellForRowAtIndexPath: when you create your cell subviews, I will check
if(self.isPreview) {
subview1.userInteractionEnabled = NO;
subview2.userInteractionEnabled = NO;
// ... etc
}
and then set in your IBAction as follows:
-(IBAction)btnPreviewTapped:(id)sender {
if(self.isPreview) {
self.isPreview = NO;
} else {
self.isPreview = YES;
}
[self.tableView reloadData];
}
-reloadData method will redraw the visible cells and their subviews, but depending on self.isPreview the subviews will or will not react on user's touch.
found another solution based on what was suggested, whick will not work for disabling user interaction for components within content view, but will disable the didSelectRowAtIndexPath, which was also expected.
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(self.bIsPreview)
return nil;
else
return indexPath;
}
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 UITextField with a tag inside a prototype cell. The UITextField is set to become first responder when the UITableView is being built and a UISwitch in the cell above is turned on.
This works if the app starts from scratch or if it was closed and restarted. Once it's loaded the [tableView reloadData] doesn't trigger the becomeFirstResponder anymore.
If the UITextField becomes first responder by touching the textfield later on, I can trigger the becomeFirstResponder event with buttons, with pop ups,...
But not with my switch any more.
Any pointers as to what I can try?
Currently, I use the didSelectRowAtIndexPath method to trigger a pop up. A nice side effect is, that when I pull up the number keypad, I can provide an ok and cancel button within the pop up instead of having to fiddle with separate buttons on the keypad. But it just seems so obviously to be a workaround.
This is how I call firstresponder when building the UITableView (which works every time the app starts from scratch):
if ([settings doubleForKey:#"limitDouble"]==0 && [settings boolForKey:#"limitBool"]==YES) {
[dailyLimitEntry becomeFirstResponder];
}
dailyLimitEntry is a UITextField which is strong so it stays around.
Just for fun I added a button and connected it to my code like this:
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
This works, too. When I use it with the switch, it's only called once the app is freshly loaded in the memory. Otherwise, my UITextField doesn't respond to the switch.
After the first comments, I found a method to check whether or not the UITableView has finished reloading
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if([indexPath row] == ((NSIndexPath*)[[settingsTableView indexPathsForVisibleRows] lastObject]).row){
//end of loading
//for example [activityIndicator stopAnimating];
NSLog(#"finished reload");
NSLog(#"%#",dailyLimitEntry);
if ([settings boolForKey:#"limitBool"]==YES) {
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
}
}
}
Fun thing though is, become first responder is only triggered the first time the switch is used after the app loaded. Initially, the switch is off. So the cell containing the UITextField is not drawn yet. Once I switch to ON, the UITextField gets drawn in the second cell and becomes first responder. If I switch OFF and ON again, I still get my log "finished reload", but the UITextField doesn't become first responder. It's driving me nuts....
Must be something about the life cycle of the app.
Rather than checking the indexPath, check the cell's class.
Here's what I do to bring up the keyboard for a title cell that's blank (when I create a new item):
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[FDSSampleTitleCell class]]) {
FDSSampleTitleCell *titleCell = (FDSSampleTitleCell *)cell;
if (titleCell.titleField.text.length == 0) {
[titleCell.titleField becomeFirstResponder];
}
}
}
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;
}