iOS7 UItableview Editing mode content overlap [duplicate] - iphone

This question already has answers here:
UITableViewCell content overlaps delete button when in editing mode in iOS7
(11 answers)
Closed 7 years ago.
When I enter editing mode of UITableView in iOS 7, the content of my cell overlaps the delete button.
I have checked UITableViewCell content overlaps delete button when in editing mode in iOS7 question but it doesn't help in my case.
I am creating my cell in tableView:cellForRowAtIndexPath method dynamically.
Please let me know if your ideas for this problem.

- (void)layoutSubviews
{
[super layoutSubviews];
self.contentView.frame = CGRectMake(0,
self.contentView.frame.origin.y,
self.contentView.frame.size.width,
self.contentView.frame.size.height);
if ((self.editing
&& (_state & UITableViewCellStateShowingDeleteConfirmationMask))){
float indentPoints = self.indentationLevel * self.indentationWidth;
self.contentView.frame = CGRectMake(50,
self.contentView.frame.origin.y,
self.contentView.frame.size.width - indentPoints - 30,
self.contentView.frame.size.height);
}
}

I actually use this fully implementation to get everything looking good:
- (void)layoutSubviews
{
[super layoutSubviews];
self.contentView.frame = CGRectMake(0,
self.contentView.frame.origin.y,
self.contentView.frame.size.width,
self.contentView.frame.size.height);
if ((self.editing
&& ((_state & UITableViewCellStateShowingEditControlMask)
&& !(_state & UITableViewCellStateShowingDeleteConfirmationMask))) ||
((_state & UITableViewCellStateShowingEditControlMask)
))
{
float indentPoints = self.indentationLevel * self.indentationWidth;
self.contentView.layer.masksToBounds = YES;
self.contentView.frame = CGRectMake(50,
self.contentView.frame.origin.y,
self.contentView.frame.size.width - indentPoints,
self.contentView.frame.size.height);
}
if ((self.editing
&& (_state & UITableViewCellStateShowingDeleteConfirmationMask)))
{
float indentPoints = self.indentationLevel * self.indentationWidth;
self.contentView.frame = CGRectMake(50,
self.contentView.frame.origin.y,
self.contentView.frame.size.width - indentPoints - 30,
self.contentView.frame.size.height);
}
}

Might be you are setting cell setBackgroundImage for Cell in cellForRowAtIndexPath (Delegate Method). Do not set this here. Set your image in:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellList.png"]]; }

Related

Merging UITableViewCells

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.

Resizing UITextView in a UITableViewCell

I'm trying to resize a UITextView that I have in a UITableViewCell. I want to resize the UITableViewCell accordingly also. My UITableViewCell resizes properly, but the UITextView does not. It ends up being just two lines instead of sizing to the the correct size. When I initialize it in the cellForRowAtIndexPath method, it looks like:
UITextView *notesTextView = [[UITextView alloc] initWithFrame:CGRectMake(83, 12, TEXTVIEW_WIDTH, 22)];
notesTextView.tag = TEXTVIEW_TAG;
notesTextView.delegate = self;
[cell.contentView addSubview:notesTextView];
When I try to modify it in the textView delegate method, I do:
CGSize size = [textView.text sizeWithFont:textView.font constrainedToSize:CGSizeMake(TEXTVIEW_WIDTH, 460) lineBreakMode:UILineBreakModeWordWrap];
NSLog(#"size: %#", NSStringFromCGSize(size)); // has the correct size
if (size.height > self.notesRowHeight) {
self.notesRowHeight = size.height;
UITextView *aTextView = (UITextView *)[self.view viewWithTag:TEXTVIEW_TAG];
CGRect textViewFrame = CGRectMake(aTextView.frame.origin.x, aTextView.frame.origin.y, TEXTVIEW_WIDTH, size.height);
aTextView.frame = textViewFrame;
aTextView.contentSize = size;
[aTextView sizeToFit];
[aTextView sizeThatFits:size];
NSLog(#"%#", NSStringFromCGRect(aTextView.frame)); // has the correct height
So what ends up happening is the tableView resize properly, and even though the textView frame is the correct size (e.g. {{83, 12}, {197, 120}}), the textView only has 2 lines. It does not end up taking the size of the UITableViewCell like I intended.
EDIT: When I try to just resize the frame for the UITextView in a normal UIView that is not a UITableViewCell, it works just fine. So I'm not sure what's different in this case.
I found the answer. I should not reload the row, but just call
[tableView beginUpdates];
[tableView endUpdates];
More information can be found at:
UITextView in a UITableViewCell smooth auto-resize shows and hides keyboard on iPad, but works on iPhone
I found the best way to solve this.
First off, of course, you're going to want to create your UITextView and add it to your cell's contentView. I created an instance variable of UITextView called "cellTextView" Here is the code that I used:
- (UITableViewCell *)tableView:(UITableView *)tableView fileNameCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
if (!cellTextView) {
cellTextView = [[UITextView alloc] initWithFrame:CGRectMake(5.0, 5.0, cell.bounds.size.width - 30.0, cell.bounds.size.height - 10.0)]; // I use these x and y values plus the height value for padding purposes.
}
[cellTextView setBackgroundColor:[UIColor clearColor]];
[cellTextView setScrollEnabled:FALSE];
[cellTextView setFont:[UIFont boldSystemFontOfSize:13.0]];
[cellTextView setDelegate:self];
[cellTextView setTextColor:[UIColor blackColor]];
[cellTextView setContentInset:UIEdgeInsetsZero];
[cell.contentView addSubview:cellTextView];
return cell;
}
Then, create an int variable called numberOfLines and set the variable to 1 in your init method. Afterwards, in your textViewDelegate's textViewDidChange method, use this code:
- (void)textViewDidChange:(UITextView *)textView
{
numberOfLines = (textView.contentSize.height / textView.font.lineHeight) - 1;
float height = 44.0;
height += (textView.font.lineHeight * (numberOfLines - 1));
CGRect textViewFrame = [textView frame];
textViewFrame.size.height = height - 10.0; //The 10 value is to retrieve the same height padding I inputed earlier when I initialized the UITextView
[textView setFrame:textViewFrame];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[cellTextView setContentInset:UIEdgeInsetsZero];
}
Finally, paste this code into your heightForRowAtIndexPath method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
float height = 44.0;
if (cellTextView) {
height += (cellTextView.font.lineHeight * (numberOfLines - 1));
}
return height;
}
I will give you an different view....
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
.
.
if(_YOUR_ROW_ && _YOUR_SECTION_)
{
cell.textView.text = Text_Of_TextView;
}
.
.
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
.
.
if(_YOUR_ROW_ && _YOUR_SECTION_)
{
UIFont * FontSize = [UIFont systemFontOfSize:14.0];
CGSize textSize = [Text_Of_TextView sizeWithFont:FontSize constrainedToSize:CGSizeMake(Width_OF_textView, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap];
return textSize.height+PADDING;
}
.
.
}
-(void)textViewDidEndEditing:(UITextView *)textView
{
[Text_Of_TextView setText:textView.text];
CGRect frame = textViewInRow.frame;
frame.size.height = textViewInRow.contentSize.height;
textViewInRow.frame = frame;
[TableView_InView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:_YOUR_ROW_ inSection:_YOUR_SECTION_]] withRowAnimation:UITableViewRowAnimationNone];
}
and also dont forget to implement auto resizing behaviour for textview
This is a simple project that demonstrates how to use auto layout to resize the cells as of iOS 8. Almost no special code required. See readme.md for key points.
project on github

Dynamically change UITextView height instead of scroll

I'm trying to create a simple Diary app. In it I have a ShowPostTableViewController where I want to display each post. In my tableView I have one section with two cells, one for the headline and one for the post's body. The headline is inside an UITextField and the body is inside a UITextView. I declare both like this:
UITextField * postHeadline;
UITextView * postText;
And i synthesize them in my implementation file. I setup the tableView's cells in the willDisplayCell method. It looks like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
tableView.allowsSelection = NO;
CGRect wholeWindow = [self.view bounds];
float headlineHeight = 40;
CGRect headlineRect = CGRectMake(10, 10, wholeWindow.size.width, headlineHeight);
CGRect bodyRect = CGRectMake(wholeWindow.origin.y, wholeWindow.origin.x,
wholeWindow.size.width, wholeWindow.size.height);
postHeadline = [[UITextField alloc] initWithFrame:headlineRect];
postText = [[UITextView alloc] initWithFrame:bodyRect];
NSString * headline = [[NSString alloc] initWithFormat:#"%#",[currentPostArray
objectAtIndex:0]];
NSString * body = [[NSString alloc] initWithFormat:#"%#",[currentPostArray
objectAtIndex:1]];
postHeadline.text = headline;
postHeadline.font = [UIFont fontWithName:#"Helvetica-Bold" size:24.0];
postText.text = body;
postText.backgroundColor = [UIColor colorWithRed:254.0/255.0 green:255.0/255.0
blue:237.0/255.0 alpha:1];
postText.font = [UIFont fontWithName:#"Georgia" size:17.0];
postText.scrollEnabled = NO;
postText.delegate = self;
if (indexPath.row == 0) {
[cell.contentView addSubview:postHeadline];
}
if (indexPath.row == 1) {
[cell.contentView addSubview:postText];
CGRect frame = postText.frame;
frame.size.height = postText.contentSize.height;
postText.frame = frame;
}
}
Yep, I'm a beginner, probably leaking memory like crazy. A question related to that. It seems like my UITextField postHeadline gets set twice, I can't erase it because it's two layers of the same text. How can I solve that?
Back to my original question. My cellForRowAtIndexPath is left petty much intact. I have sat up the delegate methods for my UITextView (think it's here the problem lies). I found a solution that almost worked here: UITextView change height instead of scroll.
They look like this:
- (void)textViewDidBeginEditing:(UITextView *)textView
{
textView.frame =CGRectMake(textView.frame.origin.x,textView.frame.origin.y,textView.
frame.size.width,textView.frame.size.height + 100);
}
This method should resize the textView:
- (void)textViewDidChange:(UITextView *)textView
{
CGFloat fontHeight = (textView.font.ascender - textView.font.descender) + 1;
CGRect newTextFrame = textView.frame;
newTextFrame.size = textView.contentSize;
newTextFrame.size.height = newTextFrame.size.height + fontHeight;
textView.frame = newTextFrame;
}
I set the row height like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath
{
NSString * body = [[NSString alloc] initWithFormat:#"%#",[currentPostArray
objectAtIndex:1]];
CGSize bodySize = [body sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0]
constrainedToSize:CGSizeMake(self.view.frame.size.width,CGFLOAT_MAX)];
if (indexPath.section == 0 && indexPath.row == 1) {
return bodySize.height + 100;
}
return 50;
}
The thing almost works. When the user hits return, the textview seems to expand, but it only works 14 times, then the cursor hides behind the keyboard.
Any ideas and tips how to solve this would be great!
Thanks
// Anders
EDIT
I solved the "headline gets set twice" problem by moving most of my willDisplayCell method code to my viewDidLoad method. And I think I have localized where the rezising problem is. I think it is in my heightForRowAtIndexPath method. It currently looks like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath
{
NSString * body = [[NSString alloc] initWithFormat:#"%#",[currentPostArray
objectAtIndex:1]];
CGSize bodySize = [body sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0]
constrainedToSize:CGSizeMake(self.view.frame.size.width,CGFLOAT_MAX)];
if (indexPath.section == 0 && indexPath.row == 1) {
return bodySize.height + 100;
}
return 50;
}
Since array and it's content gets set in the viewDidLoad method, the size stays the same. I therefore think I need to dynamically increase the cell's size after my TextView's content too. Because when I write like this:
if (indexPath.section == 0 && indexPath.row == 1) {
return 1000;
}
The cell's size increases and the user can hit "return" more times before the keyboard gets in the the way. Is there a way to increase to cells's height dynamically?
Think I solved it. These methods did the magic trick:
[self.tableView beginUpdates];
[self.tableView endUpdates];
I updated my heightForRowAtIndexPath so it looks like this:
if (indexPath.section == 0 && indexPath.row == 1) {
return postText.frame.size.height + headlineHeight;
}
return 44;
And I added these methods to viewDidChange and in viewWillAppear (to reset the sizes).
[self.tableView beginUpdates];
[self.tableView endUpdates];
That was pretty much it.

UITextView in a UITableViewCell smooth auto-resize

I have a UITextView in a UITableViewCell contentview and allow the cell to autoresize so that the entered text is fully shown - what I am trying to accomplish is an autoresizing cell like the native iOS4 Contacts app has, when you enter "notes" for contact - i.e. when the contentSize of the textView changes - I call reloadRowsAtIndexPaths and in the delegate's heightForRowAtIndexPath I provide the new height for row - this does the job, however it is not nice and smooth like the contact's app - I am almost sure Apple uses some undocumented trick in that app to make the cell's contentView expand smooth and animated without calling reloadRowsAtIndexPaths. My question is how would you suggest to implement such functionality? I hope I didn't miss any details in explanation.
Try this code below, it will be help. You don't have to use any reload functions like reloadRowsAtIndexPaths.
// textview delegate
- (void)textViewDidChange:(UITextView *)textView {
if (contentView.contentSize.height > contentRowHeight) {
contentRowHeight = contentView.contentSize.height;
[theTableView beginUpdates];
[theTableView endUpdates];
[contentView setFrame:CGRectMake(0, 0, 300.0, contentView.contentSize.height)];
}
}
// tableview delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height;
if (indexPath.row == 0)
height = kTitleRowHeight;
else
height = contentRowHeight;
return height;
}
I found the best way to solve this.
First off, of course, you're going to want to create your UITextView and add it to your cell's contentView. I created an instance variable of UITextView called "cellTextView" Here is the code that I used:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
if (!cellTextView) {
cellTextView = [[UITextView alloc] initWithFrame:CGRectMake(5.0, 5.0, cell.bounds.size.width - 30.0, cell.bounds.size.height - 10.0)]; // I use these x and y values plus the height value for padding purposes.
}
[cellTextView setBackgroundColor:[UIColor clearColor]];
[cellTextView setScrollEnabled:FALSE];
[cellTextView setFont:[UIFont boldSystemFontOfSize:13.0]];
[cellTextView setDelegate:self];
[cellTextView setTextColor:[UIColor blackColor]];
[cellTextView setContentInset:UIEdgeInsetsZero];
[cell.contentView addSubview:cellTextView];
return cell;
}
Then, create an int variable called numberOfLines and set the variable to 1 in your init method. Afterwards, in your textViewDelegate's textViewDidChange method, use this code:
- (void)textViewDidChange:(UITextView *)textView
{
numberOfLines = (textView.contentSize.height / textView.font.lineHeight) - 1;
float height = 44.0;
height += (textView.font.lineHeight * (numberOfLines - 1));
CGRect textViewFrame = [textView frame];
textViewFrame.size.height = height - 10.0; //The 10 value is to retrieve the same height padding I inputed earlier when I initialized the UITextView
[textView setFrame:textViewFrame];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[cellTextView setContentInset:UIEdgeInsetsZero];
}
Finally, paste this code into your heightForRowAtIndexPath method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
float height = 44.0;
if (cellTextView) {
height += (cellTextView.font.lineHeight * (numberOfLines - 1));
}
return height;
}

iPhone UITableView - Delete Button

I am using the 'swipe to delete' functionality of the UITableView.
The problem is I am using a customised UITableViewCell which is created on a per item basis in
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I need to alter the position of the delete button (simply to move it around 10px to the left), how would I go about doing this?
Here is my existing code for creating the cell:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cellForRowAtIndexPath");
#if USE_CUSTOM_DRAWING
const NSInteger TOP_LABEL_TAG = 1001;
const NSInteger BOTTOM_LABEL_TAG = 1002;
UILabel *topLabel;
UILabel *bottomLabel;
#endif
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//
// Create the cell.
//
cell =
[[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier]
autorelease];
#if USE_CUSTOM_DRAWING
const CGFloat LABEL_HEIGHT = 20;
UIImage *image = [UIImage imageNamed:#"trans_clock.png"];
//
// Create the label for the top row of text
//
topLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
image.size.width + 2.0 * cell.indentationWidth,
0.5 * (aTableView.rowHeight - 2 * LABEL_HEIGHT),
aTableView.bounds.size.width -
image.size.width - 4.0 * cell.indentationWidth
,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:topLabel];
//
// Configure the properties for the text that are the same on every row
//
topLabel.tag = TOP_LABEL_TAG;
topLabel.backgroundColor = [UIColor clearColor];
topLabel.textColor = fontColor;
topLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
topLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
//
// Create the label for the top row of text
//
bottomLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
image.size.width + 2.0 * cell.indentationWidth,
0.5 * (aTableView.rowHeight - 2 * LABEL_HEIGHT) + LABEL_HEIGHT,
aTableView.bounds.size.width -
image.size.width - 4.0 * cell.indentationWidth
,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:bottomLabel];
//
// Configure the properties for the text that are the same on every row
//
bottomLabel.tag = BOTTOM_LABEL_TAG;
bottomLabel.backgroundColor = [UIColor clearColor];
bottomLabel.textColor = fontColor;
bottomLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
bottomLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
//
// Create a background image view.
//
cell.backgroundView =
[[[UIImageView alloc] init] autorelease];
cell.selectedBackgroundView =
[[[UIImageView alloc] init] autorelease];
#endif
}
#if USE_CUSTOM_DRAWING
else
{
topLabel = (UILabel *)[cell viewWithTag:TOP_LABEL_TAG];
bottomLabel = (UILabel *)[cell viewWithTag:BOTTOM_LABEL_TAG];
}
topLabel.text = #"Example Text";
topLabel.textColor = fontColor;
bottomLabel.text = #"More Example Text";
bottomLabel.textColor = fontColor;
//
// Set the background and selected background images for the text.
// Since we will round the corners at the top and bottom of sections, we
// need to conditionally choose the images based on the row index and the
// number of rows in the section.
//
UIImage *rowBackground;
UIImage *selectionBackground;
NSInteger sectionRows = [aTableView numberOfRowsInSection:[indexPath section]];
NSInteger row = [indexPath row];
if (row == 0 && row == sectionRows - 1)
{
rowBackground = [UIImage imageNamed:#"topAndBottomRow.png"];
selectionBackground = [UIImage imageNamed:#"topAndBottomRowSelected.png"];
}
else if (row == 0)
{
rowBackground = [UIImage imageNamed:#"topRow.png"];
selectionBackground = [UIImage imageNamed:#"topRowSelected.png"];
}
else if (row == sectionRows - 1)
{
rowBackground = [UIImage imageNamed:#"bottomRow.png"];
selectionBackground = [UIImage imageNamed:#"bottomRowSelected.png"];
}
else
{
rowBackground = [UIImage imageNamed:#"middleRow.png"];
selectionBackground = [UIImage imageNamed:#"middleRowSelected.png"];
}
((UIImageView *)cell.backgroundView).image = rowBackground;
((UIImageView *)cell.selectedBackgroundView).image = selectionBackground;
cell.imageView.image = [UIImage imageNamed:#"Example_Image.png"];
#else
cell.text = #"Example";
#endif
return cell;
}
For me the best way to solve this was overriding -(void)layoutSubviews in MyCell:UITableViewCell
Here you can see not only the Delete button custom position, but also repositioning the Edit and Reorder controls for Edit mode
- (void)layoutSubviews
{
[super layoutSubviews];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.0f];
for (UIView *subview in self.subviews) {
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"]) {
CGRect newFrame = subview.frame;
newFrame.origin.x = 200;
subview.frame = newFrame;
}
else if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellEditControl"]) {
CGRect newFrame = subview.frame;
newFrame.origin.x = 100;
subview.frame = newFrame;
}
else if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellReorderControl"]) {
CGRect newFrame = subview.frame;
newFrame.origin.x = 200;
subview.frame = newFrame;
}
}
[UIView commitAnimations];
}
Iwat's code doesn't work for me. But this works.
- (void)willTransitionToState:(UITableViewCellStateMask)state {
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask) {
for (UIView *subview in self.subviews) {
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"]) {
subview.hidden = YES;
subview.alpha = 0.0;
}
}
}
}
- (void)didTransitionToState:(UITableViewCellStateMask)state {
[super didTransitionToState:state];
if (state == UITableViewCellStateShowingDeleteConfirmationMask || state == UITableViewCellStateDefaultMask) {
for (UIView *subview in self.subviews) {
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"]) {
UIView *deleteButtonView = (UIView *)[subview.subviews objectAtIndex:0];
CGRect f = deleteButtonView.frame;
f.origin.x -= 20;
deleteButtonView.frame = f;
subview.hidden = NO;
[UIView beginAnimations:#"anim" context:nil];
subview.alpha = 1.0;
[UIView commitAnimations];
}
}
}
}
I haven't been able to change the actual look of the delete button, but you can change the text. Perhaps you can use this to get the effect you are looking for?
Check out the following member of the UITableViewDelegate protocol:
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
Additionally, you can detect when the delete button is being displayed by subclassing UITableViewCell and overriding the the following:
- (void)willTransitionToState:(UITableViewCellStateMask)state
- (void)didTransitionToState:(UITableViewCellStateMask)state
For either of these, the state mask will be UITableViewCellStateShowingDeleteConfirmationMask when the delete button is being displayed.
Hopefully these clues will point you in the right direction.
I use a solution that on first sight looks kind of hacky but does the trick and is not relying on undocumented apis:
/**
* Transition to state
*/
-(void)willTransitionToState:(UITableViewCellStateMask)state {
if(state & UITableViewCellStateShowingDeleteConfirmationMask)
_deleting = YES;
else if(!(state & UITableViewCellStateShowingDeleteConfirmationMask))
_deleting = NO;
[super willTransitionToState:state];
}
/**
* Reset cell transformations
*/
-(void)resetCellTransform {
self.transform = CGAffineTransformIdentity;
_background.transform = CGAffineTransformIdentity;
_content.transform = CGAffineTransformIdentity;
}
/**
* Move cell around if we are currently in delete mode
*/
-(void)updateWithCurrentState {
if(_deleting) {
float x = -20;
float y = 0;
self.transform = CGAffineTransformMakeTranslation(x, y);
_background.transform = CGAffineTransformMakeTranslation(-x, -y);
_content.transform = CGAffineTransformMakeTranslation(-x, -y);
}
}
-(void)setFrame:(CGRect)frame {
[self resetCellTransform];
[super setFrame:frame];
[self updateWithCurrentState];
}
-(void)layoutSubviews {
[self resetCellTransform];
[super layoutSubviews];
[self updateWithCurrentState];
}
Basically this shifts the cell position and readjusts the visible portions.
WillTransitionToState just sets an instance variable indicating whether the cell is in delete mode. Overriding setFrame was necessary to support rotating the phone to landscape and vice-versa.
Where _background is the background view of my cell and _content is a view added to the contentView of the cell, holding all labels etc.
I don't know of any way to "move the delete button 10px to the left". However, you can animate the custom contents of your table cell around the static position of the unmovable delete button by listening for the willTransitionToState: message from a UITableViewCell sub-class see here.
To quote the docs:
Subclasses of UITableViewCell can
implement this method to animate
additional changes to a cell when it
is changing state. UITableViewCell
calls this method whenever a cell
transitions between states, such as
from a normal state (the default) to
editing mode. The custom cell can set
up and position any new views that
appear with the new state. The cell
then receives a layoutSubviews message
(UIView) in which it can position
these new views in their final
locations for the new state.
Subclasses must always call super when
overriding this method.
What you are looking for is the UITableViewCellStateShowingDeleteConfirmationMask value. This is one of those times where creating UITableViewCell subclass might be better, so from the controller you are just creating an instance of your custom cell. Then the cell can just adjust itself like animateLeft and animateRight and handle the inner workings of adjusting its own subviews.
I don't know the final solution, but as far as I tried the following code might be useful.
// subclass UITableViewCell
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableCellStateShowingDeleteConfirmationMask)
{
for (UIView *subview in self.subviews)
{
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"])
{
subview.hidden = YES;
subview.alpha = 0;
}
}
}
}
- (void)didTransitionToState:(UITableViewCellStateMask)state
{
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableCellStateShowingDeleteConfirmationMask)
{
for (UIView *subview in self.subviews)
{
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"])
{
subview.frame = CGRectMake(subview.frame.origin.x - 10, subview.frame.origin.y, subview.frame.size.width, subview.frame.size.height);
subview.hidden = NO;
[UIView beginAnimations:#"anim" context:nil];
subview.alpha = 1;
[UIView commitAnimations];
}
}
}
}