I would like to be able to drag a cell over another cell, and when I release it would effectively "merge" the cells (display a different cell). I'm not sure if a UITableView is the best control or a UICollectionView. Does anyone have any thoughts on how to proceed?
May be I didn't get u properly but as I got, u want to merge cells by dragging so implement some code for you.Have a look at this.
If u Wanna something like this...
use editing code like that :---
ViewDidLoad initializing array and set table to edit mode as:
fruitsArray=[[NSMutableArray alloc] initWithObjects:#"Apple",#"Banana",#"Mango",#"Guava",#"PineApple",#"Watermelon",#"Grapes",#"GroundNut",#"Muskmelon",#"Orange",#"Cherry",nil];
[tblView setEditing:YES];
datasources for tableView set as:->
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
if (sourceIndexPath.row!=destinationIndexPath.row) {
NSString *sourceString=[fruitsArray objectAtIndex:sourceIndexPath.row];
NSString *destinationString=[fruitsArray objectAtIndex:destinationIndexPath.row];
destinationString=[destinationString stringByAppendingFormat:#",%#",sourceString];
[fruitsArray replaceObjectAtIndex:destinationIndexPath.row withObject:destinationString];
[fruitsArray removeObjectAtIndex:sourceIndexPath.row];
[tblView reloadData];
}
}
Try this sampleCode
Here's the solution I used to develop it in pseudocode.
Add a UILongPressGestureRecognizer to the UITableView
On the UIGestureRecognizerStateBegan, use the [UITableView indexPathForRowAtPoint] in order to determine what cell is being "long pressed". You will turn this cell into the hover UITableViewCell.
Set a reference variable to the corresponding model object.
Use the UIGraphicsBeginImageContextWithOptions to render an image of the actual UITableViewCell contents. Create a UIImageView and add some custom chrome to it (shadows, etc.)
Add the custom UIImageView as a subview to the UITableView, and remove the original selected pinned UITableViewCell (removeFromSuperview).
On UIGestureRecognizerStateChanged, calculate the location of the hover UITableViewCell in the UITableView and animate the pinned cell. (You will also want to toggle the animation for the previously highlighted pinned cell).
When the user releases the LongPress, you'll want to re-order the model array, remove the underlying pinned cell, and then reload the UITableView all in a beginUpdates call.
There are a few other things to watch out for such as scrolling when you hit a boundary condition, dropping the hover cell over the original location, etc. but that's the basic gist of it. Hopefully that helps.
I used Long press gesture for this. here is sample code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:cell action:nil];
longPress.delegate = self;
[cell addGestureRecognizer:longPress];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
[gestureRecognizer addTarget:self action:#selector(moveRight:)];
}
return YES;
if([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
[gestureRecognizer addTarget:self action:#selector(tapAction:)];
}
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
- (void)moveRight:(UILongPressGestureRecognizer *)sender {
/*if (sender.view.tag==4)
{
[super setEditing:YES animated:YES];
[self.Table4 setEditing:YES animated:YES];
}
else
{
*/
UIView *view = sender.view;
int t = sender.view.tag;
CGPoint point = [sender locationInView:view.superview];
NSLog(#"its added %f", point.x);
NSLog(#"its added %f", point.y);
// view.frame = CGRectMake(sender.view.frame.origin.x, sender.view.frame.origin.y+200,200, 30);
CGPoint center = view.center;
center.x = point.x ;
center.y = point.y ;
view.center = center;
[self.view addSubview:view];
// int x = Table4.frame.origin.x;
// int y = Table4.frame.origin.y;
if (sender.state == UIGestureRecognizerStateChanged) {
CGPoint center = view.center;
center.x += point.x - _priorPoint.x;
center.y += point.y - _priorPoint.y;
NSLog(#"its Center %f", center.x);
if (center.x > Table4.frame.origin.x &&
center.x < Table4.frame.origin.x +
Table4.frame.size.width &&
center.y > Table4.frame.origin.y &&
center.y < Table4.frame.origin.y +
Table4.frame.size.height
)
{
int count = [self.rowdata count];
if (t>=100 && t<200)
{
t=t-100;
[self.rowdata insertObject:[listData objectAtIndex:t] atIndex:count];
}
else if (t>=200 && t<300)
{
t=t-200;
[self.rowdata insertObject:[listData2 objectAtIndex:t] atIndex:count];
}
else
{
t=t-300;
[self.rowdata insertObject:[listData3 objectAtIndex:t] atIndex:count];
}
//[self.rowdata addObject:[listData objectAtIndex:t]];
//[sender release];
[Table4 reloadData];
[Table1 reloadData];
[Table2 reloadData];
[Table3 reloadData];
}
view.center = center;
//}
_priorPoint = point;
}
}
I think this is helpful for you. Take some code what you want from this.
Related
This question already has answers here:
making a "load more" button in uitableviewcell?
(4 answers)
Closed 9 years ago.
I have 2000 records and i have to display only 15 records in UITableView, When User Scroll UITableView , More 15 records shold be load in table. How should I do it?
I think the Answer is : - (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGPoint offset = scrollView.contentOffset;
CGRect bounds = scrollView.bounds;
CGSize size = scrollView.contentSize;
UIEdgeInsets inset = scrollView.contentInset;
float y = offset.y + bounds.size.height - inset.bottom;
float h = size.height;
float reload_distance = 15;
if(y > h + reload_distance)
{
//Call the Method to load More Data...
}
}
Hope it will be helpful...!!!
You have to check the UIScrollView contentOffset for that (UITableView is built on UIScrollView). So, add this, to your UITableViewDelegate class:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// when reaching bottom, load more
float offs = (scrollView.contentOffset.y+scrollView.bounds.size.height);
float val = (scrollView.contentSize.height);
if (offs==val)
{
//add more data on your data array
}
}
in order to add more cells to your table when user reaches bottom of your table view.
You can use two delegate methods of UIScrollView. As UITableView comes in hierachy of UIScrollView you'll get control in this delegate methods of UIScrollView.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(#"TableView scrolling");
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"TableView Started scrolling");
}
Try above two methods. And choose the one appropriate for you. First see how NSLog are coming when you start scrolling your UITableVIew. And then write your code inside them.
By Default numberOfItemsToDisplay = 15;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (numberOfItemsToDisplay >= [self.yourArray count])
{
numberOfItemsToDisplay = [self.yourArray count];
return 1;
}
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
{
return numberOfItemsToDisplay;
}
else
{
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0)
{
static NSString *CellIdentifier = #"YourCustomCell";
YourCustomCell *objYourCustomCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (objYourCustomCell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"YourCustomCell" owner:self options:nil];
for(id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[YourCustomCell class]])
{
objYourCustomCell = (AlertsCustomCell *) currentObject;
break;
}
}
}
objYourCustomCell.lbl.text = [[self.yourArray objectAtIndex:indexPath.row]valueForKey:#"vName"];
return objYourCustomCell;
}
else
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell.contentView addSubview:[self loadMoreViewForTable:self.view]];
}
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tblAlertsList deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.section == 1)
{
numberOfItemsToDisplay = [self loadMore:numberOfItemsToDisplay arrayTemp:self.yourArray tblView:self.tblAlertsList];
[self.tblAlertsList endUpdates];
}else
{
// action if it is not LoadMore
}
}
+ (NSInteger)loadMore : (NSInteger)numberOfItemsToDisplay arrayTemp:(NSMutableArray*)aryItems tblView:(UITableView*)tblList
{
int count =0;
NSUInteger i, totalNumberOfItems = [aryItems count];
NSUInteger newNumberOfItemsToDisplay = MIN(totalNumberOfItems, numberOfItemsToDisplay + kNumberOfItemsToAdd);
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for (i=numberOfItemsToDisplay; i<newNumberOfItemsToDisplay; i++)
{
count++;
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
numberOfItemsToDisplay = newNumberOfItemsToDisplay;
[tblList beginUpdates];
[tblList insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];
if (numberOfItemsToDisplay == totalNumberOfItems) {
[tblList deleteSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationLeft];
}
NSIndexPath *scrollPointIndexPath;
if (newNumberOfItemsToDisplay < totalNumberOfItems)
{
scrollPointIndexPath = [NSIndexPath indexPathForRow:numberOfItemsToDisplay-kNumberOfItemsToAdd inSection:0];
}
else
{
scrollPointIndexPath = [NSIndexPath indexPathForRow:i-count inSection:0];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 100000000), dispatch_get_main_queue(), ^(void){
[tblList scrollToRowAtIndexPath:scrollPointIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
});
return numberOfItemsToDisplay;
}
I have to take custom cell to use this method? I have only taken UItableview
Try this:
http://www.cocoacontrols.com/controls/stableviewcontroller
use this two methods
//for refresh
- (void) addItemsOnTop {
//[self getLoginFollowingUserVideosCall];
[self refreshCompleted];
}
//for load more
- (void) addItemsOnBottom {
//[self getLoginFollowingUserVideosCall];
[self loadMoreCompleted];
}
What you have to do is load the tableview data lazily. Like load data for the tableview cell that are current visible & not all of the data at a time.
I have a textfield and a tableview. User may select textfield data from tableview or any other data.but after entering user own data my tableview must disappear.how can i achieve this.if i use resign first responder did select rowmethod is not working in tableview.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
txtcity.text = selectedCell.textLabel.text;
}
-(void)hideKeyboard //this is my gesture recogniser method
{
autocompletetableview.hidden=true;//if i didn't use this statement it enter into didselectrow method
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
autocompleteTableView.hidden=YES;
if( textField == txtcity)
{
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];// this method loads data into my tableview
return YES;
}
}
(BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if([txtcity.text isEqualToString:#""])
{
autocompleteTableView.hidden=YES;
return YES;
}
else
autocompleteTableView.hidden=NO;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return arr2.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier] autorelease];
}
cell.textLabel.text = [[arr2 objectAtIndex:indexPath.row]objectForKey:#"Name"];
cell.textLabel.font=[UIFont boldSystemFontOfSize:12];
cell.textLabel.numberOfLines=0;
return cell;
}
if i use like this if i select row it doesn't enter into did select row at index path method. help me
i am not getting where i have to use resignfirstresponder
resignFirstResponder is used to dismiss the first responder ( keyboard in the case of UITextField). If you want the tableview to disappear set the hidden property to true or remove the tableview from the view hierarchy.
i.e;
[tableView setHidden:YES]
or
[tableView removeFromSuperview];
UPDATE:
If using gesture recognizer for checking on the tap on parent view, you can do the following so that the gesture method is not fired unnecessarily.
I'm assuming you are writing all this code in the view controller for the whole thing.
UITapGestureRecognizer *tapGe = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
tapGe.numberOfTapsRequired = 1;
tapGe.delegate =self;
[self.view addGestureRecognizer:tapGe]
Then implement the following method in the view controller (Make it conform to UIGestureRecognizerDelegate protocol):
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
If(touch.view==self.view){
return YES; //If its the main view accept the touch
}else{
return NO; //Otherwise(say tableview) don't consume the touch.
}
}
I think It's useful to you.I have used custom cell and I have give my working code here.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [mainDetaileArray count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 115;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"ProductMerchantCell" owner:nil options:nil];
for (UIView *view in views)
{
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (ProductMerchantCell*)view;
//cell.img=#"date.png";
}
}
}
cell.selectionStyle=UITableViewCellSelectionStyleNone;
txtfield = [[UITextField alloc]initWithFrame:CGRectMake(104, 36, 58, 31)];
txtfield.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
txtfield.delegate = self;
txtfield.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
txtfield.returnKeyType = UIReturnKeyDone;
indexVal = indexPath.row;
[txtfield setBorderStyle:UITextBorderStyleRoundedRect];
txtfield.textAlignment = UITextAlignmentCenter;
txtfield.text = [quantity_array objectAtIndex:indexPath.row];
// NSLog(#" txtfield.text %#", txtfield.text);
[txtfield setTag:indexPath.row];
[txtfield setAutocapitalizationType:UITextAutocapitalizationTypeWords];
NSString *total_str_price1=[[mainDetaileArray objectAtIndex:indexPath.row]valueForKey:#"total_product_price"];
cell.availbl_pro_lbl.text=[NSString stringWithFormat:#"Total : %#%#",add_currnce_str,total_str_price1];
cell.title_pro_lbl.text=[[mainDetaileArray objectAtIndex:indexPath.row]valueForKey:#"product_title"];
str_price=[[mainDetaileArray objectAtIndex:indexPath.row]valueForKey:#"product_price"];
cell.price_Pro_lbl.text=[NSString stringWithFormat:#"Price : %#%#",add_currnce_str,str_price];
[cell.contentView addSubview:txtfield];
return cell;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
addtoValue = textField.text;
[quantity_array replaceObjectAtIndex:textField.tag withObject:textField.text];
// NSLog(#"quantity_array %#",quantity_array);
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
[cell.Quantity_txt resignFirstResponder];
return YES;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[cell.Quantity_txt resignFirstResponder];
}
I'm trying to create a view, where user enter his info (name, email, bio...).
To do this I'm using a group table view with 5 section (0..4), each has one cell that has a UITextField inside (except the cell in section 4 that has a UITextView inside).
When user tap on one of those textFields/textView the keyboard appears, and the cell (with the selected textField/textView) scroll to the position just above the keyboard.
My problem is with the textView at section 4, when keyboard appears it somehow automatically scroll the cell to be visible, but not exactly in the right position (half of the text view is hidden behind the keyboard).
When I try to do the scroll myself (after keyboard finish animating) I get an ugly bounce of the textView.
It seams that the cause for the ugly bounce is that the textView automatic scrolls when the keyboard appear + my scrolling. This behavior (of automatic scrolling) happens only for the textView, for example if I use a textField instead of the textView in section 4, it doesn't automatically scroll.
So the question is: how can I smoothly scroll the textView to the right position?
This is my code:
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
switch (indexPath.section) {
case 0:
[cell.contentView addSubview:self.textField1];
break;
case 1:
[cell.contentView addSubview:self.textField2];
break;
case 2:
[cell.contentView addSubview:self.textField3];
break;
case 3:
[cell.contentView addSubview:self.textField4];
break;
case 4:
// this is the text view
[cell.contentView addSubview:self.textView];
break;
default:
break;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
self.activeResponder = textField;
return YES;
}
#pragma mark - UITextViewDelegate
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
self.activeResponder = textView;
return YES;
}
- (void)keyboardWillShow:(NSNotification*)notification {
NSLog(#"keyboard show");
CGFloat animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height -= keyboardFrame.size.height;
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.tableView.frame = tableViewFrame;
} completion:^(BOOL finished) {
[self scrollToActiveResponder];
}];
}
- (void)keyboardWillHide:(NSNotification*)notification {
NSLog(#"keyboard hide");
CGFloat animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height += keyboardFrame.size.height;
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.tableView.frame = tableViewFrame;
} completion:^(BOOL finished) {
}];
}
- (NSIndexPath *)indexPathForActiveResponder {
NSIndexPath *indexPath = nil;
if (self.activeResponder == self.textField1) {
indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
}
else if (self.activeResponder == self.textField2) {
indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
}
else if (self.activeResponder == self.textField3) {
indexPath = [NSIndexPath indexPathForRow:0 inSection:2];
}
else if (self.activeResponder == self.textField4) {
indexPath = [NSIndexPath indexPathForRow:0 inSection:3];
}
else if (self.activeResponder == self.textView) {
indexPath = [NSIndexPath indexPathForRow:0 inSection:4];
}
return indexPath;
}
- (void)scrollToActiveResponder {
NSIndexPath *activeResponderIndexPath = [self indexPathForActiveResponder];
if (activeResponderIndexPath) {
[self.tableView scrollToRowAtIndexPath:activeResponderIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
}
}
I would try something like this:
.h
#interface YourViewController : UIViewController <UITextViewDelegate>
.m
//Set delegate to your textView
textView.delegate = self
#pragma mark - TextView Delegate
//TextView Became First Responder
- (void)textViewDidBeginEditing:(UITextView *)textView{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:4];
// Other way to get the IndexPath
//NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)[[textView superview] superview]];
CGRect frame = [self.tableView rectForRowAtIndexPath:indexPath];
//It only works for Portrait iPhone
CGFloat keyboardHeight = 216.0f;
CGPoint offset = CGPointMake(0, self.view.frame.size.height - keyboardHeight - frame.size.height - frame.origin.y);
[self.tableView setContentOffset:offset animated:YES];
}
I didn't test it, but it's how I would try to approach this problem. You can find more information about how calculate keyboard size here: (http://www.idev101.com/code/User_Interface/keyboard.html)
I have a custom UITableViewCell that has 1 textfield and a label on it. I would like to enable the textfield editing only when the tableview is in edit mode.
I'm using following methods to enable textfield edit mode and disable textfield edit mode. but this is not working. I'm not sure whether this is correct approach or not. If it's not the correct way, can you let me know how to disable enable textfield?
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *rowToSelect = indexPath;
EditingTableViewCell *detSelCell;
detSelCell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
detSelCell.textField.enabled = self.editing;
// Only allow selection if editing.
if (self.editing)
{
return indexPath;
}
else
{
return nil;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!self.editing)
{
return;
}
EditingTableViewCell *detcell;
detcell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
detcell.selectionStyle = style;
detcell.textField.enabled = self.editing;
also I've the following lines:
self.tableView.allowsSelection = NO; // Keeps cells from being selectable while not editing. No more blue flash.
self.tableView.allowsSelectionDuringEditing = YES; // Allows cells to be selectable during edit mode.
Please help!
--- I found the answer:
I've removed the enable/disable code from following methods:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
and added the following in custom cell.m
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.1];
[UIView setAnimationDelegate:self];
[UIView setAnimationBeginsFromCurrentState:YES];
if(editing){
textField.enabled = YES;
}else{
textField.enabled = NO;
}
[UIView commitAnimations];
}
it's working now. i'm not sure whether this is correct approach or not but its working fine.
EDIT: my bad, didn't properly read the method signatures. What you're asking is quite hard to do, because all textfields are most likely subviews of the cell or it's contentView. What you need to do is disable the cell's selectionStyle, return nil for everything in willSelect... Then allow selection during editing.
Since I've been looking for the same for some time, here's the full code achieving it
TextFieldTableViewCell.h
#interface TextFieldTableViewCell : UITableViewCell <UITextFieldDelegate> {
UITextField *textField;
}
#property (nonatomic, strong) UITextField *textField;
// add delegate/protocol to inform of change
#end
TextFieldTableViewCell.m
#import "TextFieldTableViewCell.h"
#implementation TextFieldTableViewCell
#synthesize textField;
- (void)initializeTextField {
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.textField = [[UITextField alloc] initWithFrame:CGRectZero];
self.textField.autocorrectionType = UITextAutocorrectionTypeDefault;
self.textField.enabled = NO; // not editable unless the table is in edit mode
// do all the necessary textfield setup here, font/alignment and so on
[self addSubview:self.textField];
self.accessoryType = UITableViewCellAccessoryNone;
}
// from code
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if( (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
[self initializeTextField];
}
return self;
}
// from storyboard
- (id)initWithCoder:(NSCoder *)aDecoder {
if( (self = [super initWithCoder:aDecoder])) {
[self initializeTextField];
}
return self;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.textField resignFirstResponder];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
// Extra code to be added here to notify a delegate that text has changed since cell is holding the value temporarily
// .....
UITableView *tableView = (UITableView *)self.superview;
[tableView deselectRowAtIndexPath:[tableView indexPathForCell:self] animated:YES];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect editFrame = CGRectInset(self.contentView.frame, 10, 10);
if (self.textLabel.text && [self.textLabel.text length] != 0) {
CGSize textSize = [self.textLabel sizeThatFits:CGSizeZero];
editFrame.origin.x += textSize.width + 10;
editFrame.size.width -= textSize.width + 10;
self.textField.textAlignment = UITextAlignmentRight;
} else {
self.textField.textAlignment = UITextAlignmentLeft;
}
self.textField.frame = editFrame;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
self.textField.enabled = editing;
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
[self.textField becomeFirstResponder];
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
[self.textField becomeFirstResponder];
}
}
#end
And with the setup on the table view you have the expected behavior of having a string displayed in normal mode and editable when in edit mode
self.tableView.allowsSelection = NO;
self.tableView.allowsSelectionDuringEditing = YES;
I am attempting to create a animated cell when it is selected. Everything seems to be working really odd. If I send the ButtonView to the Self.contentView of the UITableView Cell it works like it is supposed to and adds the cell in desired row but I loose button functionality at index row. If I send the buttonview to just self "UITableViewCell" I have button index row but it adds the button view in about every 10 rows.
Now the animation itself looks great when it works right. The issue is I am using a method to toggle the path selected so I can grow the cell height to twice the size when selected and stay selected until another cell is selected.
Really I have no idea where to go from here I was hoping maybe someone could help me find my mistake or have delt with something similar.
Thanks I appreciate any insight!
- (BOOL)cellIsSelected:(NSIndexPath *)indexPath {
// Return whether the cell at the specified index path is selected or not
NSNumber *selectedIndex = [selectedIndexes objectForKey:indexPath];
return selectedIndex == nil ? FALSE : [selectedIndex boolValue];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath {
[sounds PlayButtonClick:nil];
// Deselect cell ..?
//[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
// Toggle 'selected' state
BOOL isSelected = ![self cellIsSelected:indexPath];
// Store cell 'selected' state keyed on indexPath
NSNumber *selectedIndex = [NSNumber numberWithBool:isSelected];
[selectedIndexes setObject:selectedIndex forKey:indexPath];
// This is where magic happens...
[tableView beginUpdates];
[tableView endUpdates];
[sounds PlaySlide:nil];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath {
// If our cell is selected, return double height
if([self cellIsSelected:indexPath]) {
return 70 *2;
}
return 70;
}
And from my CellClass
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self == [super initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:reuseIdentifier]) {
self.contentView.clipsToBounds = YES;
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected == YES) {
NSLog(#"is selected");
[self showButtonView:!selected];
[self applyDropShadow:!selected];
// TweettextLabel.hidden = YES;
// Tweettext.hidden = NO;
}
if (selected == NO){
[self removeButtonView:!selected];
[self removeDropShadow:!selected];
//TweettextLabel.hidden = NO;
//Tweettext.hidden = YES;
NSLog(#"is NOT selected");
}
}
-(void)showButtonView:(int)view{
CGRect viewFrame = [ButtonView frame];
viewFrame.origin.y = 0;
self.ButtonView.frame = viewFrame;
[self.contentView insertSubview:self.ButtonView belowSubview:self.cellView];
[self addSubview:self.contentView];
[UIView beginAnimations:#"animateView" context:nil];
[UIView setAnimationDuration:0.3];
CGRect viewFrame1 = [ButtonView frame];
viewFrame1.origin.y = 70;
ButtonView.frame = viewFrame1;
[UIView commitAnimations];
}
-(void)removeButtonView:(int)view{
[UIView beginAnimations:#"animateView" context:nil];
[UIView setAnimationDuration:0.3];
CGRect viewFrame1 = [self.ButtonView frame];
viewFrame1.origin.y = 0;
self.ButtonView.frame = viewFrame1;
[UIView commitAnimations];
// timer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self
selector:#selector(removeLastViewFromSuper) userInfo:Nil repeats:NO];
}
-(void)applyDropShadow:(int)shadow{
self.contentView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.contentView.layer.shadowOffset = CGSizeMake(0.8f, -4.0f);
self.contentView.layer.shadowRadius = 5.0f;
self.contentView.layer.shadowOpacity = 1.0f;
}
-(void)removeDropShadow:(int)shadow{
self.contentView.layer.shadowColor = [[UIColor clearColor] CGColor];
self.contentView.layer.shadowOffset = CGSizeMake(0.0, 0.0);
self.contentView.layer.shadowRadius = 0.0;
self.contentView.layer.shadowOpacity = 0.0;
}
Add the buttonView to the cell's contentView when you create it. Show and hide it by setting the hidden or alpha property. Now the problem of not getting the button to work should go away.
Also, your dictionary with the selected indexes seems a bit overdone if you only have one cell that is selected. Just create a property "selected" of type NSIndexPath in the controller.
Finally, your selected cell repeating when you scroll is due to the re-queuing mechanism of UITableView. Make sure that you set the correct hidden property for the button in cellForRowAtIndexPath each time. This way, when a cell is recycled that has a non-hidden button, it will hide it if the index path is not the selected one.