How can I present a picker view just like the keyboard does? - objective-c

I want a UIPickerView to show up when I press a button (just like keyboard) and then go away when user taps anywhere on the screen. How can I do this? Thanks.
A bit more background: I have a UITextField called months in UITableViewCell. Now the best option for me is to put a UIPikcerView there and it will be easier for the user to just chose the month rather than having to type it out (and it's the better way). But UIPickerView looks really ugly in a UITableViewCell, not to mention I can't change it's gigantic size. So what should I do in this case?

This is how you should use UIPickerView for a textField in a UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle= UITableViewCellSelectionStyleNone;
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectMake(110, 10, 185, 30)];
textField.clearsOnBeginEditing = NO;
textField.textAlignment = UITextAlignmentRight;
textField.delegate = self;
[cell.contentView addSubview:textField];
//textField.returnKeyType = UIReturnKeyDone;
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
// if you want a UIPickerView for first row... then do the following //
// Here.. packSizePickerView is an object of UIPickerView
if (indexPath.row == 1)
{
textField.tag=0;
textField.delegate= self;
packSizePickerView.delegate = self;
packSizePickerView = [[UIPickerView alloc] init];
packSizePickerView.autoresizingMask=UIViewAutoresizingFlexibleWidth;
packSizePickerView.showsSelectionIndicator=YES;
textField.inputView = packSizePickerView;
}
// if you want to select date / months in row 2, go for UIDatePickerView //
if (indexPath.row == 1)
{
textField.tag = 1;
UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.datePickerMode = UIDatePickerModeDate;
[datePicker addTarget:self action:#selector(datePickerValueChangedd:) forControlEvents:UIControlEventValueChanged];
datePicker.tag = indexPath.row;
textField.delegate= self;
textField.inputView = datePicker;
[datePicker release];
}
}
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [myArray objectAtIndex:row];
return cell;
}
And for datePickerValueChangedd
- (void)datePickerValueChangedd:(UIDatePicker*) datePicker{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 68, 68)];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterMediumStyle;
label.text = [NSString stringWithFormat:#"%#",[df stringFromDate:datePicker.date]];
NSLog(#"I am inside the datePickerValueChanged - - %#", label.text);
[df release];
globalValue1 = label.text;
// use a global variable to copy the value from the pickerView. //
}
Now in the textFieldDidEndEditing:
-(void) textFieldDidEndEditing:(UITextField *)textField {
if (textField.tag ==0)
[textField setText: globalValue0];
if (textField.tag ==1)
[textField setText: globalValue1];
}
And to resign UIDatePicker, set the UIView as a UIControl and
resignFirstResponder

I think that you need to put your UIPickerView "outside" the viewable screen and animate it in when the button is pressed. I'm not really sure what the best way to get rid of it would be but you could probably listen for a tap on the parent view when the picker is visible and then animate it back out.

Related

Incorrect text positioning in UITableViewCell in Xcode

I have created a UITableView with two cells, username and password using the code below.
I have included a screenshot of the output the first time the view loads (the expected output) and the second time the view is shown (the incorrect output)
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:#"Cell"];
if( cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Login Ident"];
if (indexPath.row == 0) {
loginId = [[UITextField alloc] initWithFrame:CGRectMake(5, 0, 280, 21)];
loginId .placeholder = #"Email address";
loginId .autocorrectionType = UITextAutocorrectionTypeNo;
[loginId setClearButtonMode:UITextFieldViewModeWhileEditing];
cell.accessoryView = loginId;
}
if (indexPath.row == 1) {
password = [[UITextField alloc] initWithFrame:CGRectMake(5, 0, 280, 21)];
password.placeholder = #"Password";
password.secureTextEntry = YES;
password.autocorrectionType = UITextAutocorrectionTypeNo;
[password setClearButtonMode:UITextFieldViewModeWhileEditing];
cell.accessoryView = password;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
loginId.delegate = self;
password.delegate = self;
[loginId setText:[keychain objectForKey:(__bridge id)kSecAttrAccount]];
[password setText:[keychain objectForKey:(__bridge id)kSecValueData]];
[loginId addTarget:self
action:#selector(textFieldReturn:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[password addTarget:self
action:#selector(textFieldReturn:)
forControlEvents:UIControlEventEditingDidEndOnExit];
[cell.contentView addSubview:loginId];
[cell.contentView addSubview:password];
}
return cell;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[_tableView reloadData];
}
My UITextField declarations
UITextField *loginId;
UITextField *password;
If anybody is able to help me out with this, I'd really appreciate it.
With changes
You should put the code where you create the text fields inside the if (cell == nil) {} since otherwise you could be adding a second textfield to a cell that's already been created previously. If that doesn't fix the issue post back.
Also, remove:
[_tableView addSubview:loginId];
[_tableView addSubview:password];
You shouldn't add views that are meant for the cells to the tableview. And instead of making it the accessoryView of the cell, add them to the contentView
[cell.contentView addSubview:loginId];
See chat below for full resolution of the issue.

Making UITableView without IB

I'm making UITableView without IB.
My UITableView has 2 styles UITableViewCell - first row style and other row style.
I use MTLable Class instead of UILabel.
Question:
This code's results is very strange.
First cell style and other cell style is mixed when next page scrolled.
I can't find my code's faults.
I need your advice. Thanks!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//firsT cELL
if(indexPath.row==0)
{
CGRect frame=CGRectMake(0,0,80, 60);
MTLabel *label1=[[MTLabel alloc] init];
label1.backgroundColor = [UIColor grayColor];
label1.frame=frame;
label1.text=#"123";
label1.tag = 1001;
[cell.contentView addSubview:label1];
label1.autoresizingMask = UIViewAutoresizingFlexibleTopMargin &UIViewAutoresizingFlexibleWidth & UIViewAutoresizingFlexibleLeftMargin & UIViewAutoresizingFlexibleRightMargin;
label1.contentMode = UIViewContentModeTopLeft;
[label1 setTextAlignment:MTLabelTextAlignmentRight];
[label1 release];
}
else
{
CGRect frame3=CGRectMake(0,0,80, 60);
MTLabel *label3=[[MTLabel alloc]init];
label3.frame=frame3;
label3.backgroundColor = [UIColor purpleColor];
label3.text=#"100";
label3.tag = 1003;
label3.autoresizingMask = UIViewAutoresizingFlexibleTopMargin &UIViewAutoresizingFlexibleWidth & UIViewAutoresizingFlexibleLeftMargin & UIViewAutoresizingFlexibleRightMargin;
label3.contentMode = UIViewContentModeTopLeft;
[label3 setTextAlignment:MTLabelTextAlignmentRight];
[cell.contentView addSubview:label3];
[label3 release];
}
}
FTS_book *book = [items objectAtIndex:indexPath.row];
if(indexPath.row==0)
{
MTLabel *label1 = (MTLabel*)[cell viewWithTag:1001];
label1.text= [NSString stringWithFormat:#"%d", book.chapter];
}
else
{
MTLabel *label3 = (MTLabel*)[cell viewWithTag:1003];
label3.text= [NSString stringWithFormat:#"%d", book.verse];
}
return cell;
}
Use different cell Id's for those two styles.

Realtime Values in UITableViewCell from UIDatePicker

I have a UIViewController with two UI Components: UITableView and UIDatePicker. My goal is, to create a screen like the ical->add->Start & End.
I added the the tableView delegate and dateSource to my header file. In the implementation file, I want to display the current value from the datePicker in my tableCell (like the iCal Start & End screen).
My .m looks like the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[datePicker addTarget:self action:#selector(datePickerValueChanged) forControlEvents:UIControlEventValueChanged];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSMutableArray *dict = [dictionary objectForKey:#"DATA"];
if(indexPath.row == 1){
UISwitch *switchSpecifyEnd = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = switchSpecifyEnd;
[(UISwitch *)cell.accessoryView setOn:NO]; // Or NO, obviously!
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(switchSpecifyEnd)
forControlEvents:UIControlEventValueChanged];
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
}else if(indexPath.row == 3){
UISwitch *switchOpenEnd = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
cell.accessoryView = switchOpenEnd;
[(UISwitch *)cell.accessoryView setOn:NO]; // Or NO, obviously!
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(switchOpenEnd)
forControlEvents:UIControlEventValueChanged];
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
}else{
cell.textLabel.text = [dict objectAtIndex:indexPath.row];
// NSLog(#"Update Cell: %#",<but how>);
}
return cell;
}
- (void)datePickerValueChanged{
NSLog(#"Logging: %#", [NSString stringWithFormat:#"%#",datePicker.date]);
}
How can I update my tableCell with the value from the datePicker?
BR,
mybecks
For updating your table cell you need to reload your table and when your table will reload then cellForRowAtIndexPath will get call and you can update your cell text.
Suppose this is your method that gets called when you select some date in date picker
-(IBAction)setStartTimeMethod
{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE MMM dd, yyyy hh:mm a"];
self.startTimeString = [dateFormat stringFromDate:[timeStartPicker date]];
[dateFormat release];
[optionsTableView reloadData];
}

objective-c: [self.tableview reloadData] reloads data but doesnt clear older cells

i'm working on a tableview and i am newbie in dynamically creating cells (i used to create them with IB and then link them to their tableviewcell controller etc..).
Everything works great and recpected arrays are updated properly but when i fire [self.tableview reloadData] the program just redraws new values over old cells. for example if there "TEST CELL" value in a uilabel inside a cell, when i update the data to "CELL TEST" and fire the reloadData, the uilabel looks like there are two labels on top of each other and both values are visible. (its like creating two uilabel with exact same location and same size and setting their values)
and this event happens everytime i fire reloadData, with each reload, the program looks like its adding another uilabel on top of the older one. heres my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
UILabel *lblText1 = [[UILabel alloc] initWithFrame:CGRectMake(30, 5, 130, 30)];
lblText1.adjustsFontSizeToFitWidth = YES;
lblText1.backgroundColor = [UIColor clearColor];
lblText1.text = [lblText1Array objectAtIndex:indexPath.row];
[cell addSubview:lblText1];
[lblText1 release];
if(indexPath.row<3)
{
UILabel *lblText2 = [[UILabel alloc] initWithFrame:CGRectMake(170, 5, 130, 30)];
lblText2.adjustsFontSizeToFitWidth = YES;
lblText2.backgroundColor = [UIColor clearColor];
lblText2.text = nil;
lblText2.text = [spParameters objectAtIndex:indexPath.row];
[cell addSubview:lblText2];
[lblText2 release];
}
else if(indexPath.row==3){
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(170, 7, 130, 30)];
textField.adjustsFontSizeToFitWidth = YES;
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = #"please insert value";
textField.textAlignment = UITextAlignmentCenter;
textField.delegate = self;
textField.text = [spParameters objectAtIndex:indexPath.row];
[cell addSubview:textField];
[textField release];
}
else if(indexPath.row == 4)
{
UISwitch *gSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(170, 7, 130, 30)];
[gSwitch setOn:FALSE];
[gSwitch addTarget: self action: #selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:gSwitch];
[gSwitch release];
}
// Configure the cell...
return cell;
}
im releasing the components after i adding them to subviews, and i am thinking about if theres something wrong with the reuseidentifier...
Thanx for helping.
It looks as though you're populating a detail view with a fixed number of cells, so you should consider creating the instances statically, for example in viewDidLoad or in Interface Builder. You could store each cell in a separate instance variable, and just return the one that corresponds the current row each time tableView:cellForRowAtIndexPath: is called.
If you create the cells programmatically, add whatever subviews you need at that time. Otherwise, as I mentioned, you could do that in Interface Builder, which often makes it easier to set up the details of controls such as text fields. Note though that UITableViewCell already contains an instance of UILabel, so adding one yourself is redundant. Instead, just access the cell's textLabel property to get its label.

UITableView not refreshing appropriately

I have a selectedArray defined as a property in my file that holds which cells have been "checked". When displaying the cell I check whether or not the current cell value is in the selectedArray, and if it is, I display the UITableViewCellAccessoryCheckmark as the table's Accessory View.
The only problem is, when the user searches for through the UITableView using the UISearchBar, I ask the table to reloadData when they are done searching, and in the numberofRows method I see the right amount of objects in the selectedArray. However, the cellForRowatIndexPath method still displays the old checkmarks as if the selectedArray has never been updated.
Can anyone PLEASE help me? Here's my code -
NSArray *tempArray = [[NSArray alloc] init];
if(tableView == theTable) {
tempArray = [contactsArray objectAtIndex:indexPath.row];
} else {
tempArray = [searchfor_array objectAtIndex:indexPath.row];
}
NSString *cellValue = [tempArray objectAtIndex:0];
static NSString *CellIdentifier;
CellIdentifier = cellValue;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake(70, 30, 200, 20)];
name.text = [tempArray objectAtIndex:0];
name.backgroundColor = [UIColor clearColor];
[name setFont:[UIFont fontWithName:#"Helvetica-Bold" size:18]];
[cell.contentView addSubview:name];
[name release];
if([selectedArray containsObject:[tempArray objectAtIndex:0]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
[cell release];
[tempArray release];
[cellValue release];
It looks as though you're setting up the cell once and reusing it. Step through the code and you should see that the if block is entered only the first time the cell is loaded.
You'll want to adjust the cell for each row, like so:
if (cell == nil) {
// Initialize cell.
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Adjust cell for each row.
if([selectedArray containsObject:[tempArray objectAtIndex:0]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Adding to Justin's answer -
You should be adding the label in the if(cell == nil) part only. You handle the accessory view OUTSIDE of that statement. Here's what it should look like -
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake(70, 30, 200, 20)];
name.text = [tempArray objectAtIndex:0];
name.backgroundColor = [UIColor clearColor];
[name setFont:[UIFont fontWithName:#"Helvetica-Bold" size:18]];
[cell.contentView addSubview:name];
[name release];
}
if([selectedArray containsObject:[tempArray objectAtIndex:0]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}