Sunday 25 September 2011

Custom Edit & Delete

Today we shall create a TableView with custom Edit & delete button. As i think the reader will be knowing how to create project.So i don't need to bug you from stretch I will start right from customizing the tableview.

As i said of customizing a delete button most of the developer run behind with function called

-(void)willTransitionTo State:(UITableViewCellStateMask)state {
[super willTransitionToState:state];
}

Through this method we can override the delete button & their properties.




Here the Question raises is when we can override the delete button why can't we override the edit button too.Yes of course, we can override the edit button too, but the apple does not entertain for this & your application can be rejected too. Hence we need to create our own edit & delete button which works similar as TableView edit & delete.







If you want to customize only delete button here is the piece of code for it.

The willTransitionToState: is a delegate of UITableViewCell which get's called when an cell is redrawn. Using this method we can play on cell UI. Here I am placing a piece of sample which contains UIImageview to show delete button.




willTransitionToState:






-(void)willTransitionToState:(UITableViewCellStateMask)state{
    [super willTransitionToState:state];
    
if((state&UITableViewCellStateShowingDeleteConfirmationMask)
==UITableViewCellStateShowingDeleteConfirmationMask)
 {        
        for (UIView *subview in self.subviews) {
            NSLog(@"class =%@",[subview class]);

 if([NSStringFromClass([subview class]) isEqualToString:@"UITableViewCellDeleteConfirmationControl"]) {             
      UIImageView *deleteBtn = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 64, 33) ];
      [deleteBtn setImage:[UIImage imageNamed:@"delete.png"]];
    [[subview.subviews objectAtIndex:0] addSubview:deleteBtn];
    [deleteBtn release];
            }//end of if
        }//end of for
      } // end of if


And if you want to customize both edit & delete button, Here is the code.

SettingCustomCell.h


@protocol SettingCustomCellDelegate 

-(void)cellObjectSetAtIndex:(int)iIndex;
@end

@interface SettingCustomCell : UITableViewCell {





    UILabel    *mCustomLabel;

    UILabel    *mContentLabel;
    UIButton  *mEditButton;
    UIButton  *mDeleteButton;
    BOOL       mIsCellEditing;
    BOOL       isEditSet;
    BOOL       mSetCellToNormalMode;
    
    id<SettingCustomCellDelegate> delegate;

}

@property(nonatomic,retain)UILabel *customLabel;
@property(nonatomic,retain)UILabel *contentLabel;
@property (nonatomic, retain) UIButton      *editButton;
@property (nonatomic, retain) UIButton      *deleteButton;
@property (nonatomic, assign) BOOL isCellEditing;
@property (nonatomic, assign)id<SettingCustomCellDelegate> delegate;
@property (nonatomic, assign) BOOL setCellToNormalMode;
@end


Here we are using Delegate for custom cell which contains label to display text, customized Edit & Delete button & some boolean variable to check the valid condition.

SettingCustomCell.m


#import "SettingCustomCell.h"

#define M_PI   3.14159265358979323846264338327950288   /* pi */

// Our conversion definition
#define DEGREES_TO_RADIANS(angle) (angle / 180.0 * M_PI)

@implementation SettingCustomCell
@synthesize customLabel=mCustomLabel;
@synthesize contentLabel= mContentLabel;
@synthesize editButton = mEditButton;
@synthesize isCellEditing = mIsCellEditing;
@synthesize deleteButton = mDeleteButton;
@synthesize  delegate;
@synthesize setCellToNormalMode =mSetCellToNormalMode;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
   
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code.
       
        if([reuseIdentifier isEqualToString:@"CellAlbum"]) {
           
            UIButton *the_button = [[UIButton alloc] init] ;//]WithFrame:CGRectMake(5, 5, 30, 30)];
             [the_button setImage:[UIImage imageNamed:@"delete2"] forState:UIControlStateNormal];
             [the_button addTarget:self action:@selector(editButtonAction:)                  forControlEvents:UIControlEventTouchUpInside];
           
            self.editButton =the_button;
            [self.contentView addSubview:the_button];
            [the_button release];
          
            UIButton *the_delete = [[UIButton alloc] init];
           [the_delete setBackgroundImage:[UIImage imageNamed:@"btn_delete_normal"] forState:UIControlStateNormal];
            [the_delete setBackgroundImage:[UIImage imageNamed:@"btn_delete_pressed"] forState:UIControlStateSelected];
             [the_delete setTitle:@"Delete" forState:UIControlStateNormal];
            [the_delete setTitle:@"Delete" forState:UIControlStateSelected];
            [the_delete addTarget:self.superview action:@selector(deleteButtonAction:) forControlEvents:UIControlEventTouchUpInside];
           
            self.deleteButton = the_delete;
            [self.contentView addSubview:the_delete];
            [the_delete release];
        }
       
       
        UILabel* the_CustomLabel = [[UILabel alloc]init];//WithFrame:CGRectMake(5, 5, 170,20)];
        the_CustomLabel.backgroundColor=[UIColor clearColor];
        the_CustomLabel.font=[UIFont fontWithName:@"Helvetica-Bold" size:16];
        //the_CustomLabel.textColor = [UIColor whiteColor];
        [self.contentView addSubview:the_CustomLabel];
        self.customLabel = the_CustomLabel;
        [the_CustomLabel release];
       
       
        UILabel* the_ContentLabel = [[UILabel alloc]init];//WithFrame:CGRectMake(5, 25, 170, 18)];
        the_ContentLabel.backgroundColor=[UIColor clearColor];
         the_ContentLabel.font=[UIFont fontWithName:@"Helvetica-Bold" size:12];
        //the_ContentLabel.textColor = [UIColor whiteColor];
        [self.contentView addSubview:the_ContentLabel];
        self.contentLabel = the_ContentLabel;
        [the_ContentLabel release];
    }
    return self;
}


- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
    }

-(void)layoutSubviews {
    [super layoutSubviews];
   
    if(self.isCellEditing ) {
        if(self.setCellToNormalMode) {
            [self.editButton setFrame:CGRectMake(5, 5, 30, 30)];
            [self.contentLabel setFrame:CGRectMake(40, 25, 170, 18)];
            [self.customLabel setFrame:CGRectMake(40, 5, 170, 20)];
       
            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.20f];
            [UIView setAnimationCurve:UIViewAnimationCurveLinear];
            [UIView setAnimationBeginsFromCurrentState:YES];
            CGAffineTransform transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
            self.editButton.transform = transform;
            [self.deleteButton setFrame:CGRectMake(322, 5, 57, 30)];
            [UIView commitAnimations];
                       
        }
       
        else {

            [UIView beginAnimations:nil context:NULL];
            [UIView setAnimationDuration:0.20f];
            [UIView setAnimationCurve:UIViewAnimationCurveLinear];
            [UIView setAnimationBeginsFromCurrentState:YES];
            [self.editButton setFrame:CGRectMake(5, 5, 30, 30)];
            [self.contentLabel setFrame:CGRectMake(40, 25, 170, 18)];
            [self.customLabel setFrame:CGRectMake(40, 5, 170, 20)];
            //[self.deleteButton setFrame:CGRectMake(230, 5, 90, 30)];
            [UIView commitAnimations];
        }
        isEditSet = YES;
        }
    else {
       
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.00f];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [self.editButton setFrame:CGRectMake(-40, 5, 30, 30)];
        [self.contentLabel setFrame:CGRectMake(10, 25, 170, 18)];
        [self.customLabel setFrame:CGRectMake(10, 5, 170, 20)];
        [self.deleteButton setFrame:CGRectMake(322, 5, 57, 30)];
        [UIView commitAnimations];
        isEditSet = NO;
    }
}

- (void)dealloc {
    self.customLabel = nil;
    self.contentLabel = nil;
    self.editButton = nil;
    self.deleteButton = nil;
    self.isCellEditing = 0;
    self.delegate = nil;
[super dealloc];
}


-(void)editButtonAction:(id)sender {
    UIButton *resultButton = (UIButton *)sender;
    if(isEditSet) {
        [delegate cellObjectSetAtIndex:[sender tag]];
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.30f];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        [UIView setAnimationBeginsFromCurrentState:YES];       
       
        CGAffineTransform transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));
        resultButton.transform = transform;
        [self.deleteButton setFrame:CGRectMake(230, 5, 57, 30)];
       [UIView commitAnimations];
        [self.accessoryView setHidden:YES];
        isEditSet =NO;
       }
   
    else {
       
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.30f];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        [UIView setAnimationBeginsFromCurrentState:YES];
        CGAffineTransform transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
        resultButton.transform = transform;
        [self.deleteButton setFrame:CGRectMake(322, 5, 57, 30)];
        [UIView commitAnimations];
        [self.accessoryView setHidden:NO];
       isEditSet = YES;
    }
   
}
@end

--------------------------------------------end of Custom cell-------------------------------------------------------



#import <UIKit/UIKit.h>
#import "SettingCustomCell.h"
@interface custom_edit_tableViewController : UIViewController<SettingCustomCellDelegate> {
    UIBarButtonItem *rightBarButton;
    UITableView        *editTableView;
    BOOL isTableEditing;
    int indexNumber;
    NSMutableArray *alarmArray;
}
@property (nonatomic, retain) IBOutlet UIBarButtonItem *rightBarButton;
@property (nonatomic,retain) IBOutlet UITableView    *editTableView;
-(IBAction)editButton:(id)sender;
@end

--------------------------------------------------------------------------------------------------------------------------



#import "custom_edit_tableViewController.h"

@implementation custom_edit_tableViewController
@synthesize editTableView;
@synthesize rightBarButton;

- (void)viewDidLoad {
    [super viewDidLoad];
       isTableEditing = NO;
    indexNumber = -1;
    alarmArray = [[NSMutableArray alloc]initWithObjects:@"Apple",@"Mac",@"iMac",@"iPhone",@"iPod",@"iPad",@"Mac Book",nil];

    //UIBarButtonItem *right = self.navigationController.navigationItem.rightBarButtonItem;
    NSLog(@"frame =%f",self.navigationController.navigationItem.rightBarButtonItem.width);
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    self.rightBarButton =nil;
    self.editTableView = nil;
}
- (void)dealloc {
    self.rightBarButton =nil;
    self.editTableView = nil;
    [super dealloc];
}

-(IBAction)editButton:(id)sender{
    UIBarButtonItem *barItem = (UIBarButtonItem *)sender;
        if([[barItem title] isEqualToString:@"Edit"]){
        [barItem setTitle:@"Done"];
        isTableEditing = YES;
        [self.editTableView reloadData];
        }
    else {
        [barItem setTitle:@"Edit"];
         isTableEditing = NO;
        [self.editTableView reloadData];
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{return [alarmArray count];}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"CellAlbum";
    SettingCustomCell *cell = (SettingCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[SettingCustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
        cell.delegate = nil;
        cell.delegate = self;
    }
   if(isTableEditing)
    {cell.isCellEditing = NO;
       
        //Anand Kumar
        /*Description:  To perfrom Edit & Delete Action uncomment the below code
        */
        cell.isCellEditing = YES;
        if(indexNumber == indexPath.row) {
            cell.setCellToNormalMode = YES;
            }
        else {
            cell.setCellToNormalMode = NO;
            }      
    }
    else {       
        cell.isCellEditing = NO;
       [cell setEditing:NO];
    }
    [cell.editButton setTag:indexPath.row];
    [cell.deleteButton setTag:indexPath.row+100];
   [cell.customLabel setText:[alarmArray objectAtIndex:indexPath.row]];
    [cell.contentLabel setText:@"abc"];
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
    return cell;
}
-(void)deleteButtonAction:(id)sender {
    NSLog(@"delete row at index =%d",[sender tag]-100);
}

-(void)cellObjectSetAtIndex:(int)iIndex {
   
    if(indexNumber > -1 && indexNumber != iIndex) {
        NSIndexPath* updatePath = [NSIndexPath indexPathForRow:indexNumber inSection: 0];
        [self.editTableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:updatePath,nil] withRowAnimation:UITableViewRowAnimationNone];
      }
    indexNumber = iIndex;
   }

@end

-------------------------------------------------------------------------------------------------------------------------




Here is the source code link & this link for reference 

More book on Objective-c

NSPredicate with Object

Cocoa-Touch ships with an super-useful class that will help you search through your lists of objects just like they were coming from a database. The class is called NSPredicate which also works with Core Data. This is very powerful stuff, especially what you are working with data intensive applications.

Here Is How NSPredicate Works

First off, keep in mind that generally we are using NSArray to manage lists of objects in our apps. The objects that NSArray stores for us are made up of properties like name, length and whatever is required for the objects in question. NSPredicate works by defining queries that select objects from an array based on the properties of the objects in the array.
Here are the steps required to search arrays with NSPredicate:

Find or create an NSArray full of objects with interesting properties
Create an NSPredicate object with the search query that you want to use
You can use this NSPredicate object to either filter the array or create a new array with a subset of data

Essentially, these three steps are all it takes to filter an array. Of course, you will need some other pieces in place to do some meaningful work. Next, I will show you a concrete example of using NSPredicate with a custom class.

NSPredicate Search Example

Here Is The Type Of Object We Will Query

The first thing I did for this example was to create a custom class called Predicate_Data that could correspond to an individual row of data in a database.


Anyway, here is the class definition for Predicate_Data:

#import <Foundation/Foundation.h>

@interface Predicate_Data : NSObject {
    int primaryKey;
    NSString *name;
    NSNumber *rollNo;
}

@property(nonatomic, assign) int primaryKey;
@property(nonatomic, retain) NSString *name;
@property(nonatomic, retain) NSNumber *rollNo;

@end



Create Your NSArray & Fill It With Predicate_Data Objects

In effect, we are creating a list of objects that is a bit like a database table. Note here that listOfItems is declared as an NSMutableArray at the top of the file where this code would be located since it needs to stay in scope though-out the lifecycle of objects made from the class:
listOfItems = [[NSMutableArray alloc] init];

for(int i=0;i< 5;i++)
{
Predicate_Data *the_object = [[Predicate_Data alloc]init];
the_object.primaryKey = i;
the_object.name  = [NSString stringWithFormat:@"String%d",i];
the_object.rollNo = [NSNumber numberWithString:@"3102%d",i]; 
[listOfItems addObject:the_object];

[the_object release];
 
}

To summarize, we create an array and then create each object and add each object to the array. Here is what the results would look like if we were to present this array in a table view:

Get A Subset Of Data Instead!

So here is what you have been waiting for. To display a subset of the dataset you would need to code an NSPredicate using a query string. For instance, if we wanted to find out who in our dataset were programmers we could do something like this:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == 'String1'"];
[listOfItems filterUsingPredicate:predicate];


All you need to do is create the NSPredicate with our query and send the filterUsingPredicate message to your array using the NSPredicate object as an argument. If we tack this query to the end of our code and again run an app using a table view it would look like this:

 NSPredicate Query Examples:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"rollNo >= 31021"];
[listOfItems filterUsingPredicate:predicate];


Find everyone who has a name that begins with “T”:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH 'T'"];
[listOfItems filterUsingPredicate:predicate];


Other few examples on NSPredicate

Simple match

The simplest example is when you just need an exact match against a single value. This is a fairly meaningless example in this case but illustrates the basic technique:

    NSString *match = @"Kumar.";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];


The query string is simply “SELF == %@” where SELF refers to the each element in the array. To use the predicate we apply it to the array of file names using filterArrayUsingPredicate:. In this trivial (and pointless) example the results array would contain a single string “Kumar.” assuming that file existed in the directory.

Wildcard match

To match using a wildcard string the query can use like instead of the comparison operator and include the “*”  (match zero or more characters) or “?” (match exactly 1 character) as wildcards as follows:
    NSString *match = @"Anand*.";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];



In this case the results array would contain the filenames that match Anand*. (e.g. Anand-001., Anand-002., etc.).