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;
Related
I met with an requirement in which I had UISearchBar as like follows.
Step : 1 (Initial look of the SearchBar)
Step : 2 (User types string and immediate Search)
Step : 3 (Selecting any of them in the Search List)
Step : 4 (Adding the button on the SearchBar)
Step : 5 (Finally Action on the Button)
This might continue. I mean to say is he can enter the text further more but the functionality should be the same.
Could anyone please help me ? Please, I am in a need.
UPDATE
You can watch this same functionality on your iMac Finder Search
This is what i have tried.
#import "ViewController.h"
#import "customPopOverController.h"
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#property (strong, nonatomic) UIView *searchView;
#property (strong, nonatomic) UITableView *sampleView;
#property (strong, nonatomic) NSMutableArray *arrayForListing;
#property (strong, nonatomic) UITextField *txtFieldSearch;
#end
#implementation ViewController
#synthesize searchView = _searchView;
#synthesize customPopOverController = _customPopOverController;
#synthesize txtFieldSearch = _txtFieldSearch;
#synthesize sampleView = _sampleView;
#synthesize arrayForListing = _arrayForListing;
#synthesize btnforExtra = _btnforExtra;
- (void)viewDidLoad
{
[super viewDidLoad];
self.arrayForListing = [[NSMutableArray alloc]init];
[self loadTheSearchView];
[self applyUIStyle];
}
- (void)loadTheSearchView
{
self.searchView = [[UIView alloc]initWithFrame:CGRectMake(20, 100, 280, 44)];
[self.searchView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:self.searchView];
[self placeTheTextView];
}
- (void)placeTheTextView
{
self.txtFieldSearch = [[UITextField alloc]initWithFrame:CGRectMake(25, 9, 230, 30)];
[self.txtFieldSearch setDelegate:self];
[self.searchView addSubview:self.txtFieldSearch];
}
- (void)applyUIStyle
{
self.searchView.layer.cornerRadius = 20.0f;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField.text.length!=0)
{
[self.arrayForListing removeAllObjects];
[self.arrayForListing addObject:[NSString stringWithFormat:#"File Contains %#",textField.text]];
[self callThePop];
}
return YES;
}
- (void)callThePop
{
UIViewController *contentViewController = [[UIViewController alloc] init];
contentViewController.contentSizeForViewInPopover = CGSizeMake(self.searchView.frame.size.width, 50);
self.sampleView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, contentViewController.contentSizeForViewInPopover.width, contentViewController.contentSizeForViewInPopover.height)];
[self.sampleView setDelegate:self];
[self.sampleView setDataSource:self];
[self.sampleView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLineEtched];
[self.sampleView setBackgroundColor:[UIColor clearColor]];
[contentViewController.view addSubview:self.sampleView];
self.customPopOverController = [[customPopOverController alloc]initWithContentViewController:contentViewController];
self.customPopOverController.delegate = self;
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(callYourMethod:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self.sampleView addGestureRecognizer:swipeRight];
[self.customPopOverController presentPopoverFromRect:self.searchView.frame inView:self.view permittedArrowDirections:(UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown| UIPopoverArrowDirectionLeft|UIPopoverArrowDirectionRight) animated:YES];
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table View Delegate Methods
#pragma mark
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.arrayForListing.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifer = #"Cell";
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
}
cell.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[cell.textLabel setTextAlignment:UITextAlignmentCenter];
[cell.textLabel setNumberOfLines:0];
[cell.textLabel setLineBreakMode:UILineBreakModeCharacterWrap];
cell.textLabel.text = [self.arrayForListing objectAtIndex:indexPath.row];
[cell.textLabel setFont:[UIFont fontWithName:#"TrebuchetMS" size:14]];
cell.textLabel.textColor = [UIColor whiteColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.customPopOverController)
{
[self.customPopOverController dismissPopoverAnimated:YES];
}
UITableViewCell * cell = (UITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
if (self.txtFieldSearch.text.length == 0)
{
self.txtFieldSearch.text = cell.textLabel.text;
}
else
{
self.btnforExtra = [[UIButton alloc]initWithFrame:CGRectMake(10+(buttonsCount*45), 8, 45, 25)];
[self.btnforExtra setBackgroundColor:[UIColor colorWithRed:0.503 green:0.641 blue:0.794 alpha:1.000]];
[self.btnforExtra setTitle:self.txtFieldSearch.text forState:UIControlStateNormal];
[self.btnforExtra setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.btnforExtra.layer setCornerRadius:8.0f];
[self.txtFieldSearch setFrame:CGRectMake(self.btnforExtra.frame.origin.x+self.btnforExtra.frame.size.width+10, 9, 230, 30)];
self.txtFieldSearch.text = #"";
[self.searchView addSubview:self.btnforExtra];
buttonsCount++;
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.editing == UITableViewCellEditingStyleDelete)
{
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
[self.arrayForListing removeObjectAtIndex:indexPath.row];
[tableView endUpdates];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"IndexPath.row == %i", indexPath.row);
}
#pragma mark - custom PopOver Delegate Methods
#pragma mark
- (BOOL)popoverControllerShouldDismissPopover:(customPopOverController *)thePopoverController
{
return YES;
}
- (void)popoverControllerDidDismissPopover:(customPopOverController *)thePopoverController
{
self.customPopOverController = nil;
}
#end
DISCLAIMER: this solution is deeply flawed, probably in many ways. It's the first solution that I came up with and I've done VERY little optimization on it (aka none).
So, I was bored, and I came up with something that I think fits the bill. Keep in mind that this only does the display of what you're asking about (and it does it somewhat poorly at that), it does not handle the actual search functionality as I'm not sure what you're searching. It also has some static values programmed in (such as file types array, and I dropped the view controller into a UINavigationController and did some static sizes based on that) that you'll want to change. I make use of WYPopoverController, which can be found here: WYPopoverController. Let me know how it works for you- feel free to critique the hell out if it.
ViewController.h
#interface ViewController : UIViewController <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
{
}
ViewController.m
#import "ViewController.h"
#import "WYPopoverController.h"
#import "SearchButton.h"
#import <QuartzCore/QuartzCore.h>
#interface ViewController () <WYPopoverControllerDelegate>
{
UITextField *searchField;
UIView *searchesView;
UIScrollView *scrollView;
WYPopoverController *newSearchController;
WYPopoverController *existingSearchController;
NSMutableArray *buttonsArray;
SearchButton *activeButton;
NSArray *kindsArray;
NSMutableArray *matchedKinds;
// using UITableViewController instead of just UITableView so I can set preferredContentSize on the controller
UITableViewController *searchTable;
UITableViewController *existingTable;
}
#end
#implementation ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
searchField = [[UITextField alloc] initWithFrame:CGRectMake(20, 75, 280, 30)];
searchField.borderStyle = UITextBorderStyleRoundedRect;
searchField.autocorrectionType = UITextAutocorrectionTypeNo;
searchField.delegate = self;
[self.view addSubview:searchField];
searchesView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, searchField.frame.size.height)];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 0, searchField.frame.size.height)];
[scrollView addSubview:searchesView];
searchField.leftView = scrollView;
searchField.leftViewMode = UITextFieldViewModeAlways;
[searchField becomeFirstResponder];
kindsArray = [NSArray arrayWithObjects:#"Audio", #"Video", #"Other", #"Text", nil];
matchedKinds = [[NSMutableArray alloc] init];
buttonsArray = [[NSMutableArray alloc] init];
[searchField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Text Field Delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[newSearchController dismissPopoverAnimated:YES completion:^{
[self popoverControllerDidDismissPopover:newSearchController];
}];
return YES;
}
// not technically part of the TF delegate, but it fits better here
- (void)textFieldDidChange:(UITextField *)tf
{
if(tf.text.length > 0)
{
if(newSearchController == nil)
{
searchTable = [[UITableViewController alloc] init];
searchTable.tableView.delegate = self;
searchTable.tableView.dataSource = self;
searchTable.preferredContentSize = CGSizeMake(320, 136);
newSearchController = [[WYPopoverController alloc] initWithContentViewController:searchTable];
newSearchController.delegate = self;
newSearchController.popoverLayoutMargins = UIEdgeInsetsMake(10, 10, 10, 10);
newSearchController.theme.arrowHeight = 5;
searchTable.tableView.tag = 1;
[newSearchController presentPopoverFromRect:searchField.bounds
inView:searchField
permittedArrowDirections:WYPopoverArrowDirectionUp
animated:YES
options:WYPopoverAnimationOptionFadeWithScale];
}
[matchedKinds removeAllObjects];
for(NSString *type in kindsArray)
{
NSRange foundRange = [[type lowercaseString] rangeOfString:[tf.text lowercaseString]];
if(foundRange.location != NSNotFound)
{
// Found a match!
[matchedKinds addObject:type];
}
}
[searchTable.tableView reloadData];
}
else
{
[newSearchController dismissPopoverAnimated:YES completion:^{
[self popoverControllerDidDismissPopover:newSearchController];
}];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(tableView.tag == 1)
return 2;
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView.tag == 1)
{
if(section == 0)
return 1;
return [matchedKinds count];
}
return 3;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if(tableView.tag == 1)
{
if(section == 0)
return #"Filenames";
else
return #"Kinds";
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 30.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"reuser"];
// Configure the cell...
if(tableView.tag == 1)
{
if(indexPath.section == 0)
{
cell.textLabel.text = [NSString stringWithFormat:#"Name matches: %#", searchField.text];
}
else
{
cell.textLabel.text = [matchedKinds objectAtIndex:indexPath.row];
}
}
else
{
if(indexPath.row == 0)
{
switch (tableView.tag) {
case 2:
cell.textLabel.text = #"Filename";
break;
default:
cell.textLabel.text = #"Kind";
break;
}
}
else if(indexPath.row == 1)
cell.textLabel.text = #"Everything";
else
cell.textLabel.text = #"<Delete>";
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView.tag == 1) // new search table tapped
{
SearchButton *searchedButton = [SearchButton buttonWithType:UIButtonTypeSystem];
if(indexPath.section == 0)
{
searchedButton.type = ButtonTypeName;
searchedButton.searchedString = searchField.text;
}
else
{
searchedButton.type = ButtonTypeKind;
searchedButton.searchedString = [matchedKinds objectAtIndex:indexPath.row];
}
searchedButton.defaulted = YES;
searchedButton.titleLabel.font = [UIFont systemFontOfSize:14.0f];
[searchedButton setTitleColor:[UIColor darkTextColor]
forState:UIControlStateNormal];
[searchedButton addTarget:self
action:#selector(buttonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[searchedButton setBackgroundColor:[UIColor colorWithWhite:0.9f alpha:1.0f]];
searchedButton.layer.cornerRadius = 5.0f;
searchedButton.clipsToBounds = YES;
[buttonsArray addObject:searchedButton];
activeButton = searchedButton;
searchField.text = #"";
[self updateButtonsFromCreation:YES];
[newSearchController dismissPopoverAnimated:YES completion:^{
[self popoverControllerDidDismissPopover:newSearchController];
}];
}
else // text field of an existing search
{
switch (indexPath.row) {
case 0:
activeButton.defaulted = YES;
break;
case 1:
activeButton.defaulted = NO;
break;
default:
[buttonsArray removeObject:activeButton];
break;
}
[self updateButtonsFromCreation:NO];
[existingSearchController dismissPopoverAnimated:YES completion:^{
[self popoverControllerDidDismissPopover:existingSearchController];
}];
}
}
#pragma mark - Popover delegate
- (void)popoverControllerDidDismissPopover:(WYPopoverController *)controller
{
if(controller == newSearchController)
{
newSearchController = nil;
}
else
{
existingSearchController = nil;
}
}
#pragma mark - Other functions
- (void)updateButtonsFromCreation:(BOOL)creation
{
[[searchesView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
float widthTotal = 0;
for(SearchButton *button in buttonsArray)
{
NSString *buttonText;
if(button.defaulted)
{
if(button.type == ButtonTypeName)
buttonText = #"Name: ";
else
buttonText = #"Kind: ";
}
else
buttonText = #"Any: ";
buttonText = [buttonText stringByAppendingString:button.searchedString];
[button setTitle:buttonText forState:UIControlStateNormal];
CGSize buttonSize = [buttonText sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:14.0f]}];
button.frame = CGRectMake(widthTotal + 2, 2, buttonSize.width + 4, searchField.frame.size.height - 4);
widthTotal += button.frame.size.width + 2;
[searchesView addSubview:button];
}
searchesView.frame = CGRectMake(0, 0, widthTotal, searchesView.frame.size.height);
scrollView.frame = CGRectMake(0, 0, ((widthTotal > 200) ? 200 : widthTotal), scrollView.frame.size.height);
scrollView.contentSize = CGSizeMake(widthTotal, scrollView.frame.size.height);
if(creation)
{
scrollView.contentOffset = CGPointMake(activeButton.frame.origin.x, 0);
}
}
- (void)buttonTapped:(SearchButton *)sender
{
activeButton = sender;
existingTable = [[UITableViewController alloc] init];
existingTable.tableView.delegate = self;
existingTable.tableView.dataSource = self;
existingTable.preferredContentSize = CGSizeMake(160, 90);
existingSearchController = [[WYPopoverController alloc] initWithContentViewController:existingTable];
existingSearchController.delegate = self;
existingSearchController.popoverLayoutMargins = UIEdgeInsetsMake(10, 10, 10, 10);
existingSearchController.theme.arrowHeight = 5;
existingTable.tableView.tag = sender.type;
[existingSearchController presentPopoverFromRect:sender.frame
inView:scrollView
permittedArrowDirections:WYPopoverArrowDirectionUp
animated:YES
options:WYPopoverAnimationOptionFadeWithScale];
}
#end
SearchButton.h
typedef enum {ButtonTypeName = 2,
ButtonTypeKind = 3} ButtonType;
#interface SearchButton : UIButton
#property (nonatomic) ButtonType type;
#property (nonatomic) BOOL defaulted;
#property (nonatomic, retain) NSString *searchedString;
#end
SearchButton.m
no changes to default generated
I am trying to create a hovering UITableViewController over a UIViewController. I have managed to open the TableView over the ViewController. (Picture)
When first loading the view the data is loaded and I can see the rows for split second, but then it disappears. I understand that I must be assigning something over the actual view in the memory. However I can't fins what I am doing wrong.
Here is how I try to do it:
I create it as a object and load it with animation
BINotificationView *notifView = [[BINotificationView alloc] init];
notifView.view.frame = CGRectMake(10, 10, 300, 400);
[notifView.tableView setDataSource:notifView];
[notifView.tableView setDelegate:notifView];
[notifView setResultSet:_notifSet];
notifView.view.layer.masksToBounds = YES;
[self.view addSubview:notifView.view];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2];
[notifView.view setAlpha:1.0];
[UIView commitAnimations];
[UIView setAnimationDuration:0.0];
When view is loaded the tableview is populated (with same cell identifier in storyboard)
#interface BINotificationView ()
#end
#implementation BINotificationView
#synthesize resultSet;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.view.alpha = 0.0;
self.view.layer.cornerRadius = 5;
self.view.layer.borderWidth = 3.0f;
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (resultSet.count) {
return resultSet.count;
}
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"notif";
NotificationCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[NotificationCell alloc] init];
cell.frame = CGRectMake(0, 0, 300, 80);
}
cell.notification = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 280, 80)];
[cell addSubview:cell.notification];
[cell.notification setFont:[UIFont fontWithName:#"AvenirNextCondensed-Regular" size:16]];
if (resultSet.count) {
BINotification *obj = [resultSet objectAtIndex:indexPath.row];
cell.notification.text = obj.type;
}
else {
cell.notification.text = #"Empty List";
}
[cell.notification setEditable:NO];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.0;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
My UITableViewCell is defined as
#interface NotificationCell : UITableViewCell
#property (nonatomic, retain) IBOutlet UITextView *notification;
#end
#implementation NotificationCell
#synthesize notification;
#end
The UITableViewController .h file is like this
#interface BINotificationView : UITableViewController
#property (nonatomic, strong) NSMutableArray *resultSet;
#end
Thanks for your help
It looks like notifView is released when its scope ends. But its view is added as a subview, this may explain why it is seen for a while. The solution is to extend the scope of notifView, try making it a property of the controller which adds notifView's view as a subview.
notification = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 270, 80)];
[self addSubview:notification];
Add this in your UITableViewCell file
How can I adapt this to be able to make multiple selections? and get the selected ones
- (id)initWithCellIdentifier:(NSString *)cellID {
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID])) {
UITableViewCell *cell=self;
UIImage *cry = [UIImage APP_CRYSTAL_SELECT];
self.leftImage = [[[UIImageView alloc] initWithImage:cry] autorelease] ;
[self.contentView addSubview:leftImage];
}
And the selected method is:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if(selected)
{
NSArray *subviews=[self.contentView subviews];
for(UIView* view in subviews){
if([view isEqual:self.leftImage]){
[self.leftImage setHighlightedImage:[UIImage APP_CRYSTAL_SELECTED]];
}
}
}
else
{
NSArray *subviews=[self.contentView subviews];
for(UIView* view in subviews){
if([view isEqual:self.leftImage]){
[self.leftImage setHighlightedImage:[UIImage APP_CRYSTAL_SELECT]];
}
}
}
}
For multiple selection, setup an NSMutableArray ivar (selectedIndexPaths in this case) to hold the items that are selected. In didSelectRowAtIndexPath add or remove indexPaths to this array.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(![self.selectedIndexPaths containsObject:indexPath])
[self.selectedIndexPaths addObject:indexPath];
else
[self.selectedIndexPaths removeObject:indexPath];
}
Use selectedIndexPaths later to do whatever you wish! Cheers!
-Akshay
Edit: I'm starting a bounty on this one, as I'm looking for a "cleaner" solution with a UITableViewCell subclass, rather than messing with the UITableView delegate and datasource. Ideally, I'd like to see how could I also handle the UISlider events. Thanks!
I am using a group-styled UITableView and I have several cells that look like this:
Now, while I'm in editing mode, I'd like to have a UISlider that sets the value of the right UILabel, so that the result would look like this:
Could someone point me to the right direction? I'm not even sure if I should do that by subclassing UITableViewCell or in IB. Code snippets would be highly appreciated :)
Being a sucker for bounties, i sat down and experimented a bit. This is what i have found to be the cleanest solution :
You will make a custom cell class. As i read from your post, you have no problem with this, and I belive it really is the only way.
In the header file:
#interface TableCellSlider : UITableViewCell {
UISlider *cellSlider;
}
In the main file :
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
cellSlider = [[UISlider alloc] initWithFrame:CGRectMake(200, 10, 100, 20)];
[self addSubview:cellSlider];
cellSlider.hidden = YES;
}
return self;
}
- (void)didTransitionToState:(UITableViewCellStateMask)state
{
if (self.editing) {
cellSlider.hidden = NO;
} else {
cellSlider.hidden = YES;
}
}
- (float)getValue {
return cellSlider.value;
}
As for the table and the cell height, add this to the table script :
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[self.tableView beginUpdates];
[super setEditing:editing animated:YES];
[self.tableView endUpdates];
//[self.tableView reloadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.editing) {
return 50;
} else {
return 30;
}
}
This should do the trick. You can use the getValue on the cells, so you don't have to synthesize the sliders, and they will hide/reappear for whatever reason the cells become editable.
Best of luck with your project :]
First of all, create a new Navigation-based Project, then create a new class file named CustomCell.h and CustomCell.m, respectively.
Copy and paste this code into your RootViewController.m file:
#import "RootViewController.h"
#import "CustomCell.h"
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.rightBarButtonItem=self.editButtonItem;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
cell.mainLabel.text=#"ValueName";
return cell;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView.editing){
return 70;
}
return 44;
}
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
return;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)dealloc
{
[super dealloc];
}
#end
CustomCell.h:
#import <UIKit/UIKit.h>
#interface CustomCell : UITableViewCell {
}
#property (nonatomic, retain) UILabel *mainLabel;
#property (nonatomic, retain) UILabel *detailLabel;
#property (nonatomic, retain) UISlider *slider;
#end
CustomCell.m:
#import "CustomCell.h"
#implementation CustomCell
#synthesize mainLabel, detailLabel, slider;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
slider = [[UISlider alloc] initWithFrame:CGRectMake(10, 12, 280, 0)];
slider.alpha = 0;
slider.maximumValue = 30;
slider.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
[self.contentView addSubview:slider];
[slider addTarget:self action:#selector(sliderChanged:) forControlEvents:UIControlEventTouchDragInside];
[slider release];
mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 12, 150, 20)];
mainLabel.highlightedTextColor = [UIColor whiteColor];
mainLabel.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:mainLabel];
[mainLabel release];
detailLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.bounds.size.width-180, 12, 150, 20)];
detailLabel.textAlignment=UITextAlignmentRight;
detailLabel.text = [NSString stringWithFormat:#"%i", lroundf(slider.value)];
detailLabel.highlightedTextColor = [UIColor whiteColor];
detailLabel.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:detailLabel];
[detailLabel release];
}
return self;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationBeginsFromCurrentState:YES];
if(editing){
slider.alpha = 1;
slider.userInteractionEnabled=YES;
}else{
slider.alpha = 0;
slider.userInteractionEnabled=NO;
}
[UIView commitAnimations];
}
-(IBAction) sliderChanged:(id) sender{
detailLabel.text=[NSString stringWithFormat:#"%i", lroundf(slider.value)];
}
- (void)dealloc
{
[super dealloc];
}
#end
Compile and run and you have a perfectly fine version of the controls you wanted. I even implemented animations as smooth as butter. Have fun!
EDIT:
If you do want to use the editing-controls, you must not implement the following method and have to adjust the frame of the labels and the slider.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
you need to reconfigure your cell in the delgate method named
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
this method is called when ever user swaps the cell for deleting
where you can find the cell by the method of UITableView
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
and then reconfigure it
for more information refer developer documentation
As far as my knowledge is concerned you can add your slider when the editing begins. I mean in the following method.
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath*)indexPath
{
/* Add your slider. */
}
Thanks.
I'm just blindly shooting, as I have not implemented it by my own, But, Reloading table with the new size may help, you can overwrite, following method while being in edit mode..
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return (int)yourHeight;
}
UITableViewController doesn't scroll automatically anymore?
When you have a text field inside a UITableViewController cell that would be obfuscated by the keyboard, if the field receive the focus, the UITableViewController scroll (or it should) the field to a visible area. I have a simple UITableViewController inside a simple UITabBarController, the changes ive made in the UITableViewController are the background color and the section header views... any ideas? There is the code... ;)
//
// SolicitaTaxiPhone.h
// ExpressTaxi
//
// Created by Paulo Ferreira on 11/5/10.
// Copyright 2010 MobileLifeUtils.com. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface SolicitaTaxiPhone : UITableViewController <UITextFieldDelegate> {
NSArray *aGruposCamposSolicitacao;
}
#end
//
// SolicitaTaxiPhone.m
// ExpressTaxi
//
// Created by Paulo Ferreira on 11/5/10.
// Copyright 2010 MobileLifeUtils.com. All rights reserved.
//
#import "SolicitaTaxiPhone.h"
#import <QuartzCore/QuartzCore.h>
#implementation SolicitaTaxiPhone
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
self = [super initWithStyle:style];
self.title = #"Solicitar Táxi";
self.navigationItem.title = #"Solicitar Táxi";
//[self.tableView setBackgroundColor:[UIColor blackColor]];
UITextField *tfOrigem = [UITextField new];
[tfOrigem setFrame:CGRectMake(10.0f, 10.0f, 240.0f, 25.0f)];
[tfOrigem setClearButtonMode:UITextFieldViewModeWhileEditing];
[tfOrigem setAutocorrectionType:UITextAutocorrectionTypeNo];
[tfOrigem setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[tfOrigem setReturnKeyType:UIReturnKeyDone];
UIButton *btLocalizacaoAtual = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btLocalizacaoAtual setFrame:CGRectMake(250.0f, 1.0f, 40.0f, 40.0f)];
[btLocalizacaoAtual setTitle:#"GPS" forState:UIControlStateNormal];
NSArray *aCamposOrigem = [NSArray arrayWithObjects:tfOrigem, btLocalizacaoAtual, nil];
NSDictionary *dCamposOrigem = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"Endereço de Origem", aCamposOrigem, nil]
forKeys:[NSArray arrayWithObjects:#"titulo", #"componentes", nil]
];
UITextField *tfComplemento = [UITextField new];
[tfComplemento setFrame:CGRectMake(10.0f, 10.0f, 280.0f, 25.0f)];
[tfComplemento setClearButtonMode:UITextFieldViewModeWhileEditing];
[tfComplemento setAutocorrectionType:UITextAutocorrectionTypeNo];
[tfComplemento setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[tfComplemento setReturnKeyType:UIReturnKeyDone];
NSArray *aCamposComplemento = [NSArray arrayWithObjects:tfComplemento, nil];
NSDictionary *dCamposComplemento = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"Complemento do Endereço", aCamposComplemento, nil]
forKeys:[NSArray arrayWithObjects:#"titulo", #"componentes", nil]
];
UITextField *tfDestino = [UITextField new];
[tfDestino setFrame:CGRectMake(10.0f, 10.0f, 240.0f, 25.0f)];
[tfDestino setClearButtonMode:UITextFieldViewModeWhileEditing];
[tfDestino setAutocorrectionType:UITextAutocorrectionTypeNo];
[tfDestino setAutocapitalizationType:UITextAutocapitalizationTypeWords];
[tfDestino setReturnKeyType:UIReturnKeyDone];
//[tfDestino setDelegate:self];
UIButton *btReversoDestino = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btReversoDestino setFrame:CGRectMake(250.0f, 1.0f, 40.0f, 40.0f)];
[btReversoDestino setTitle:#"RD" forState:UIControlStateNormal];
NSArray *aCamposDestino = [NSArray arrayWithObjects:tfDestino, btReversoDestino, nil];
NSDictionary *dCamposDestino = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"Endereço de Destino", aCamposDestino, nil]
forKeys:[NSArray arrayWithObjects:#"titulo", #"componentes", nil]
];
aGruposCamposSolicitacao = [[NSArray arrayWithObjects:dCamposOrigem, dCamposComplemento, dCamposDestino, nil] retain];
return self;
}
#pragma mark -
#pragma mark View lifecycle
/*
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
*/
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return [aGruposCamposSolicitacao count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 1;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSArray *aCamposSecao = [[aGruposCamposSolicitacao objectAtIndex:indexPath.section] valueForKey:#"componentes"];
for (id componenteAtual in aCamposSecao) {
[cell.contentView addSubview:componenteAtual];
}
return cell;
}
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 50;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *vwTitulo = [[UILabel alloc] init];
[vwTitulo setBackgroundColor:[UIColor clearColor]];
UIView *vwBackgroundTitulo = [[UIView alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 300.0f, 30.0f)];
[vwBackgroundTitulo setBackgroundColor:[UIColor yellowColor]];
vwBackgroundTitulo.layer.cornerRadius = 10.0f;
UILabel *lblTitulo = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 00.0f, 300.0f, 28.0f)];
[lblTitulo setBackgroundColor:[UIColor clearColor]];
[lblTitulo setTextColor:[UIColor blackColor]];
[lblTitulo setTextAlignment:UITextAlignmentCenter];
[lblTitulo setFont:[UIFont boldSystemFontOfSize:18.0f]];
[lblTitulo setText:[[aGruposCamposSolicitacao objectAtIndex:section] valueForKey:#"titulo"]];
[vwBackgroundTitulo addSubview:lblTitulo];
[vwTitulo addSubview:vwBackgroundTitulo];
return vwTitulo;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
#pragma mark -
#pragma mark UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSLog(#"Chamou essa jossa!");
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[self.tableView scrollToRowAtIndexPath:[self.tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
[self isFirstResponder];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
either – scrollToRowAtIndexPath:atScrollPosition:animated: or
– scrollToNearestSelectedRowAtScrollPosition:animated:
are probably what you want.
I discovered that the problem it's not the UITableViewController, as soon as I discover the real problem I'll post it here.
The problem was the existence of 3 UIViewControllers nested without need...
Thanks for the help!