UITableView slide not editable row with editable rows Xcode iPhone - iphone

I'm developing an iPhone app and I have one problem. I have a UITableView with a few editable rows(
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{ )
and one not editable row. If I click edit, the editable rows slide a bit to the right and there is a red round button at the left of it, but the not editable row doesn't slide at all. Is there a way to also slide it to the right but without the red button at the left? It doesn't look that nice at the moment. I hope someone can help me with this:)

I am not sure if it's a good idea to change the default behavior of the tableView.
But if you really want to, you could e.g. use indentation.
// Might be target of button
- (void) setEditingMode
{
tableView.editing = YES;
[tableView reloadData];
}
// Might be target of button
- (void) resetEditingMode
{
tableView.editing = NO;
[tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = ...;
....
Boolean cellIsEditable = ...;
if( tableView.editing && !cellIsEditable )
{
cell.indentationWidth = ...; // (please experiment to find the exact value)
cell.indentationLevel = 1;
}
else
{
cell.indentationLevel = 0;
}
}

Subclass the UITableViewCell and slide the uneditable row yourself.
#interface MyHistoryTableViewCell : UITableViewCell
#end
#implementation MyHistoryTableViewCell : UITableViewCell
#define CELL_SLIDE_WIDTH 32 // found empirically
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
if ( self.editingStyle == UITableViewCellEditingStyleNone ) { // not editable
CGRect frame = self.frame;
UITableView *tableView = ((UITableView *)(self.superview));
if ( tableView.editing ) { // going to editing mode
frame.origin.x = CELL_SLIDE_WIDTH;
frame.size.width = tableView.frame.size.width - CELL_SLIDE_WIDTH;
} else { // ending editing
frame.origin.x = 0;
frame.size.width = tableView.frame.size.width;
}
[UIView animateWithDuration:0.3 animations:^{ // match the tableView slide duration
self.frame = frame;
}];
}
}
#end
If you have subviews that need to be anchored to the right of the cell (e.g., a button that should not slide), then do
mySubview.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; // anchors to the right margin
Also, you have to be creative when setting the subview's frame.origin.x. I experimented with many values until I found something that worked (the value made no sense to me).

Related

how to increase and resize the tableview cell in iphone?

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 50;
}
In this place, i would like to add a button dynamically to increase the height of the cell, so when user clicks upon that button it should be increase the height of cell and then click again to resize the height.
I want to something like :
-(void)IncreaseCell
{
UIButton *DownArrow = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[DownArrow addTarget:self
action:#selector(IncreaseCell:)
forControlEvents:UIControlEventTouchDown];
//[DownArrow setTitle:#"Arrow" forState:UIControlStateNormal];
DownArrow.frame = CGRectMake(121.0, 112.0, 72.0, 37.0);
[cell.contentView addSubview:DownArrow];
UIImage *buttonDown = [UIImage imageNamed:#"friendsDownArrowButton.png"];
[DownArrow setBackgroundImage:buttonDown forState:UIControlStateNormal];
[cell.contentView addSubview:DownArrow];
}
You will need to create a NSMutableArray as an instance variable, in which you keep track of all the cells, that you want to have "increased".
#interface YourTableViewController : UITableViewController {
NSMutableDictionary *increasedRows;
}
Remember to alloc/init that variable.
To get your cell increased:
-(void)increseCell: (BOOL)status forIndexPath: (NSIndexPath*)indexPath {
[increasedRows setObject:[NSNumber numberWithBool:status] forKey: indexPath];
[self.tableView beginUpdates]; //Delete if you don't want it animated
[self.tableView endUpdates]; //Delete if you don't want it animated
// [self.tableView reloadData]; //Uncomment if you don't want it animated
}
You change your tableView: heightForRowAtIndexPath: declaration to check this dictionary for your indexPath.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Check if cell is increased, return custom height
if([[increasedRows objectForKey:indexPath] boolValue]) {
return 150;
}
// Cell isn't increased so return regular height
return 50;
}
This method will allow you to do it for every row individually and allows you to animate it.
You need to change your implementation of heightForRowAtIndexPath.
Add some storage, like an array, which holds flags indicating if a row is expanded or not. When a button is tapped, get the index path of the cell that it is on and edit the array contents to set / unset the flag. Reload the table view (or the row for the changed index path).
All you have to do is declare a variable:
#interface yourViewController ()
{
CGFloat cellSize;
}
And in your heightForRowAtIndexPath::
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return cellSize;
}
in your viewDidLoad
-(void)viewDidLoad
{
[super viewDidLoad];
cellSize = 50;
}
and last in your increaseCell:
-(void)IncreseCell {
cellSize += 10;
[self reloadData];
}
what i did in one of my project is i created a custom cell and add subview to it statically
1 st scene non collapsed view
custom cell shows only button on click of which it will show extended view by increasing size of cell..
i.e on click of button you should increse size of cell using function..
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL check=[[booleanArrayofrows objectAtIndex:indexPath.row] boolValue];
if (check)
{
return 180; ..expanded view height
}
return 40; collapse view height
}
}

Cost of iterating over cells in a UITableView

Inside each UITableViewCell of my UITableView, I have a UIScrollView. The scroll view is setup so that when the user swipes right a menu will appear. This is similar to the behavior of the cells in the iPhone Twitter app. When a user swipes upon another cell I iterate over all visible cells to tell the UIScrollView to scroll back to the cell content (i.e. its initial position). The iteration is done in the scrollViewWillBeginDragging method with the following code:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if( [scrollView tag] == 90 ) {
NSLog(#"Dragging a scroll view inside a cell!");
for (UITableViewCell *cell in self.tableView.visibleCells) {
[(UICellContentScrollView *)[cell viewWithTag:90] scrollRectToVisible:CGRectMake(0.0f, 0.0f, 320.0f, [cell frame].size.height) animated:YES];
}
}
}
In the method viewDidDisappear I iterate again over all cells to reset various things like so:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
for( NSUInteger section = 0; section < [[self tableView] numberOfSections]; section++ ) {
for( NSUInteger row = 0; row < [[self tableView] numberOfRowsInSection:section]; row++ ) {
UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
// resetting cell here
}
}
}
My question is if I am (a) going about this the right way and (b) does anyone have any recommendations on a better solution considering the table view may be storing up 50 (no more than 100) items.
Check out the NSNotification documentation. You could register all of your UITableViewCell objects to receive a notification you could call something like "cellWasSwiped" or "needToResetCells" or whatever. Then whenever you want to reset the cells you just post the notification. All of your UITableViewCell objects that are registered to receive it will get the notification and can then call whatever method you need.

UISearchDisplayController frame for UITableView in iOS

I have a UITable that has a UISearchDisplayController.
The UITable is less than the width of the screen (it's 280px width centered).
When I tap on the search bar, the UISearchDisplayController table is all the way to the left of the screen.
Even when changing the frame of the table of the UISearchDisplayController, I still get the same positioning.
I set the frame here:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
tableView.backgroundColor = [UIColor colorWithRed:29.0/255.0 green:30.0/255.0 blue:32.0/255.0 alpha:1];
tableView.rowHeight = self.myTable.rowHeight;
tableView.frame = myTable.frame;
NSLog(#"search table origin: %f",tableView.frame.origin.x);
}
Even weirder, when I log the search table position at the end, it shows 16. However, it is at position 0 in the view.
Any help is appreciated.
I answered my own question. The frame needs to be set in this delegate method:
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
tableView.frame = self.myTable.frame;
}
Try this Simple Method:
//--Search display controller frame
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
[tableView setFrame:CGRectMake(my_table.frame.origin.x, tableView.frame.origin.y, my_table.frame.size.width, my_table.frame.size.height)];
}

Figure out section of a section header when tapped in a UITableView

I have a UITableView with custom views for section headers. I added a UITapGestureRecognizer to the customer sections header views to detect when someone has tapped on a section header.
How do I figure out which section the section headers belong to?
Thanks in advance.
The easiest way is to designate a property on your section header view class to hold the section index, then assign the index to that property in -tableView:viewForHeaderInSection: like this:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// CustomHeaderView *headerView = ...
headerView.section = section;
// ...
return headerView;
}
Then have the gesture callback look at that property.
The action method that you are providing must have the following signature :
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
And a gestureRecognizer have the following properties :
Getting the Recognizer’s State and View
state property
view property
enabled property
So basically you can ask for the view that it is attached to and interrogate that view.
in the viewDidLoad section insert your gestureRecognizer:
- (void)viewDidLoad
{
(...)
UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTapTable:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.numberOfTouchesRequired = 1;
[self.yourTable addGestureRecognizer:doubleTap];
(...)
}
If you only want to detect single tap change doubleTap.numberOfTapsRequired to 1.
Then add the following method. This will check if the tapped point is inside section header:
-(void)doubleTapTable:(UISwipeGestureRecognizer*)tap
{
if (UIGestureRecognizerStateEnded == tap.state)
{
CGPoint p = [tap locationInView:tap.view];
NSIndexPath* indexPath = [yourTable indexPathForRowAtPoint:p];
if(indexPath){ // user taped a cell
// whatever you want to do if user taped cell
} else { // otherwise check if section header was clicked
NSUInteger i;
for(i=0;i<[yourTable numberOfSections];i++) {
CGRect headerViewRect = [yourTable rectForHeaderInSection:i];
BOOL isInside = CGRectContainsPoint (headerViewRect,
p);
if(isInside) {
// handle Header View Selection
break;
}
}
}
}
}
A bit late to the party here, but this can be a difficult problem to solve, especially if (as #klyngbaek mentions in the comments), you are adding/removing sections. Changing a tag or custom index property on the header UIView by reloading entire sections can result in ugly animations.
Try this as a callback method for the gesture recognizer that's attached to each header UIView (admittedly hackey):
- (void)headerTapped:(UITapGestureRecognizer *)sender{
NSInteger section = 0;
for(int counter = 0; counter < [self.tableViewOfInterest numberOfSections]; counter++){
if([[self.tableViewOfInterest headerViewForSection:counter] frame].origin.y == sender.view.frame.origin.y){
section = counter;
break;
}
}
}
Basically, when asking a UITableView for each section header, it returns an instance of the header with the frame set to the header's position in the table. Comparing this with the frame of the UITapGestureRecognizer's view property will result in a match at some point (no pun intended)!
You can add button to header and set tag to button something like this:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:
(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.height, tableView.frame.size.width)];
UIButton *button = [[UIButton alloc] initWithFrame:headerView.frame];
button.tag = section;
[button addTarget:self action:#selector(detectSection:) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubView:button];
return headerView;
}
-(void)detectSection:(UIButton *)sender {
switch(sender.tag) {
//your code
}
}

How to indent custom uilabel in a UITableViewCell when editing

I have a custom uitableviewcell that i would like to indent when I turn on this:
[self.boatsDisplay setEditing:YES animated:YES];
Could anyone provide me a hint or some guidance?
Thanks
You'll need to subclass UITableViewCell and override -layoutSubviews. When the cell's editing bit is set to YES, -layoutSubviews will automatically be invoked. Any changes made within -layoutSubviews are automatically animated.
Consider this example
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat xPosition = 20.0f; // Default text position
if (self.editing)
xPosition = 40.0f;
CGRect textLabelFrame = self.textLabel.frame;
textLabelFrame.origin.x = xPosition;
self.textLabel.frame = textLabelFrame;
}
In your UITableViewDelegate you can use the tableView:indentationLevelForRowAtIndexPath: method:
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView.editing == YES){
return 1; // or higher integer
} else {
return 0;
}
}
if you want to check for your custom cell only you can add &&[[tableView cellForRowAtIndexPath:indexPath] isKindOfClass:yourTableViewCell] in the if condition.