I am re-using an Objective-C code where there is a dynamic tableView that display bluetooth devices in the area.
I would like to add a button on each row of this tableView that would trigger an action and display a content at the bottom of the screen.
The current and interesting part of code is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
CLBeacon *beacon = (CLBeacon*)[self.beacons objectAtIndex:indexPath.row];
NSString *proximityLabel = #"";
switch (beacon.proximity) {
case CLProximityFar:
proximityLabel = #"Far";
break;
case CLProximityNear:
proximityLabel = #"Near";
break;
case CLProximityImmediate:
proximityLabel = #"Immediate";
break;
case CLProximityUnknown:
proximityLabel = #"Unknown";
break;
}
cell.textLabel.text = proximityLabel;
NSString *detailLabel = [NSString stringWithFormat:#"Major: %d, Minor: %d, RSSI: %d, UUID: %#",
beacon.major.intValue, beacon.minor.intValue, (int)beacon.rssi, beacon.proximityUUID.UUIDString];
cell.detailTextLabel.text = detailLabel;
return cell;
}
I am wondering what would be the best way to do it, and where to insert the button in this code.
I am not familiar with Objective-C dev and looking for all kind of example/illustration for this problem.
You can add your button in your cell's init part, that is
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// create your button and add it to your cell
UIButton *button = ....
[cell.contentView addSubview:button];
}
Related
I've been banging my head against the wall whole day now. I have UITableViewController which has two sections: first on is optional, depending if the is data to show; second is always and has 5 cells. All cells have UILabel and UITextField (field has sometime picker or datepicker, depending on data). When I change orientation to landscape whole table is going crazy and is mixing fields texts between rows and also between sections while scrolling. I've read it has something to do with reusing cells, but nothing helped so far. Even if I keep new data model for storing fields content it still gets misplaced...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
SearchCell *cell = (SearchCell*)[tableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
cell.valueField.delegate = self;
if (_attributesArray && indexPath.section == 0) {
cell.titleLabel.text = _attributesArray[indexPath.row][#"name"];
cell.valueField.text = _attributesArray[indexPath.row][#"value"];
switch ([_attributesArray[indexPath.row][#"type"] intValue]) {
case ATTR_INT:{
cell.valueField.keyboardType = UIKeyboardTypeNumberPad;
}
break;
case ATTR_DEC:{
cell.valueField.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
}
break;
case ATTR_DATE:{
cell.valueField.inputView = self.datePicker;
}
break;
case ATTR_TEXT:{
cell.valueField.keyboardType = UIKeyboardTypeDefault;
}
break;
case ATTR_BOOL:{
// cell.valueField.inputView = self.choicePicker;
}
break;
}
}else{
switch (indexPath.row) {
case 0:{
cell.titleLabel.text = #"Name/Link";
cell.valueField.keyboardType = UIKeyboardTypeDefault;
}
break;
case 1:{
cell.titleLabel.text = #"Full text";
cell.valueField.keyboardType = UIKeyboardTypeDefault;
}
break;
case 2:{
cell.titleLabel.text = #"Uploaded before";
cell.valueField.inputView = self.datePicker;
}
break;
case 3:{
cell.titleLabel.text = #"Uploaded after";
cell.valueField.inputView = self.datePicker;
}
break;
case 4:{
cell.titleLabel.text = #"Document type";
// cell.valueField.inputView = self.choicePicker;
}
break;
}
}
return cell;
}
It's very annoying issue, thanks in advance
UPDATE
I tried this, but no luck so far. I put labels and fields values in two arrays of dictionaries, for two sections. It's mixing now textfields values in both portrait and landscape orientations...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
SearchCell *cell;
if (_attributesArray && indexPath.section == 0) {
cell = (SearchCell*)[tableView dequeueReusableCellWithIdentifier:#"Attribute" forIndexPath:indexPath];
if (cell == nil) {
cell = [[SearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Attribute"];
}
cell.titleLabel.text = _attributesArray[indexPath.row][#"name"];
cell.valueField.text = _attributesArray[indexPath.row][#"value"];
cell.valueField.delegate = self;
}else{
cell = (SearchCell*)[tableView dequeueReusableCellWithIdentifier:#"Property" forIndexPath:indexPath];
if (cell == nil) {
cell = [[SearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Property"];
}
cell.titleLabel.text = _propertiesArray[indexPath.row][#"name"];
cell.valueField.text = _propertiesArray[indexPath.row][#"value"];
cell.valueField.delegate = self;
}
return cell;
}
Maybe a better way to go about this is to have 2 custom cells and assign 2 different identifiers to it?
static NSString *oneTypeIdentifier = #"nonFeaturedCells";
static NSString *anotherTypeIdentifier = #"FeaturedCells";
and when you do create the cells to...
SomeCell *cell = [tableView dequeueReusableCellWithIdentifier:oneTypeIdentifier];
if(cell==nil)
{
cell=[[SomeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:oneTypeIdentifier];
}
I'm new to iOS developing. I have a UITableViewCell which has three buttons and they were not appearing to be pressed to touch. I implemented the following code. The pressing appeared to have been solved but the scrolling have been disabled. Here's my code to make buttons appear to be pressed on touch. The loop in the code is important otherwise the table will not behave the way I want it to. Here's my code for cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"customCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *textLabel = (UILabel *) [cell.contentView viewWithTag:5];
switch ([indexPath section]) {
case 0:
textLabel.text = [patientRoom objectAtIndex:[indexPath row]];
break;
case 1:
textLabel.text = [patientsBathroom objectAtIndex:[indexPath row]];
break;
}
if (shown){
if (selectedIndexPath.row == indexPath.row)
comments.hidden = NO;
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// Configure the cell...
for (id obj in cell.subviews){
if ([NSStringFromClass([obj class]) isEqualToString:#"UITableViewCellScrollView"]){
UIScrollView *scroll = (UIScrollView *) obj;
scroll.delaysContentTouches = NO;
break;
}
}
return cell;
}
Basically I need two things to work with the cells in my view, a tap and a tap and hold gesture. I have the tap and hold gesture working like so:
-(void) longTap:(UILongPressGestureRecognizer *)gestureRecognizer
{
NSLog(#"gestureRecognizer= %#",gestureRecognizer);
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan)
{
NSLog(#"longTap began");
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [myTable indexPathForRowAtPoint:p];
if (indexPath == nil)
{
NSLog(#"long press on table view but not on a row");
}
else
{
NSLog(#"long press on table view at row %d", indexPath.row);
switch (indexPath.row)
{
case 0:
del.tableRowNumber = 0;
break;
case 1:
del.tableRowNumber = 1;
break;
case 2:
del.tableRowNumber = 2;
break;
case 3:
del.tableRowNumber = 3;
break;
case 4:
del.tableRowNumber = 4;
break;
case 5:
del.tableRowNumber = 5;
break;
}
}
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"MealPlannerRecipeTypeViewController"];
[self.navigationController pushViewController:controller animated:YES];
}
}
I need this gesture to set a value in a singleton class to a certain value depending on what row is selected. No matter what row is selected this value is always 0?! Can anyone tell me why?
Second part of the question is that one of my tableview delegates looks like this:
- (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];
RecipeInfo *recipeInfo = recipeInfoArray[indexPath.row];
cell.textLabel.text = recipeInfo.name;
// Add long tap for the main tiles
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTap:)];
[cell addGestureRecognizer:longPressGesture];
}
return cell;
}
Every row in my table view has the same information as the first one? Why is this?
Thanks
Since you're using reusable cells, and you've changed the textLabel inside the if() alloc-init block.
Move the cell.textLabel.text line out of the if() { } block right above return cell;
if (cell == nil) {
cell = ...
}
RecipeInfo *recipeInfo = recipeInfoArray[indexPath.row]
cell.textLabel.text = recipeInfo.name;
return cell;
}
EDIT: The above was for question 2.
The first question, about your gesture recognizer...looking at your code, you have
[gestureRecognizer locationInView:self.tableView];
But later you write
[myTable indexPathForRowAtPoint
Did you think to change locationInView:self.tableView to locationInView:myTable
You set cell values only when you created it. The "dequeue" can return a already instantiated cell. I purpose that move if bracket.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
// Add long tap for the main tiles
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTap:)];
[cell addGestureRecognizer:longPressGesture];
}
RecipeInfo *recipeInfo = recipeInfoArray[indexPath.row];
cell.textLabel.text = recipeInfo.name;
...
Good day!
I have a UITableView and two cells with its corresponding UITextField. I created the UITextField via for loop:
- (UITextField *)createInformationTextField:(NSString *)createInformationTextField createInformationPlaceholder:(NSString *)createInformationPlaceholder
{
for (int i = 0; i < 2; i++) {
informationTextField = [[UITextField alloc] initWithFrame:CGRectMake(120, 12, 170, 30)];
informationTextField.autocapitalizationType = UITextAutocapitalizationTypeWords;
informationTextField.autocorrectionType = UITextAutocorrectionTypeNo;
informationTextField.placeholder = createInformationPlaceholder;
informationTextField.text = createInformationTextField;
informationTextField.adjustsFontSizeToFitWidth = YES;
informationTextField.clearButtonMode = UITextFieldViewModeAlways;
informationTextField.tag = i;
}
return informationTextField;
}
My cellForRowAtIndexPath:
- (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];
}
NSString *name;
NSString *address;
switch (indexPath.section) {
case 0:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch (indexPath.row) {
case 0:
informationTextField = [self createInformationTextField:name createInformationPlaceholder:[NSString stringWithFormat:#"%d", informationTextField.tag]];
cell.textLabel.text = #"Name";
[cell addSubview:informationTextField];
break;
case 1:
informationTextField = [self createInformationTextField:address createInformationPlaceholder:[NSString stringWithFormat:#"%d", informationTextField.tag]];
cell.textLabel.text = #"Address";
[cell addSubview:informationTextField];
break;
default:
break;
}
break;
case 1:
switch (indexPath.row) {
case 0:
cell.textLabel.text = #"State";
break;
default:
break;
}
break;
default:
break;
}
informationTextField.delegate = self;
return cell;
}
I set the UITableView placeholder to display its corresponding tag, and its working fine.
Screenshot:
The problem is in my textFieldDidEndEditing:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
switch (textField.tag) {
case 0:
NSLog(#"Name Field. The tag is %d", textField.tag);
break;
case 1:
NSLog(#"Address Field. The tag is %d", textField.tag);
break;
default:
break;
}
}
I tried to output its tag again after a user inputs something in the UITextField, but this is what I see
2013-06-06 17:36:53.050 UITableUITextField[20387:c07] Address Field. The tag is 1
2013-06-06 17:36:55.636 UITableUITextField[20387:c07] Address Field. The tag is 1
Apple's Documentation
You are calling createInformationTextField method to create textfield. I think you are invoking this method from each cell. So when you are calling this method, it enters to the for loop, and after two loops, it return the textfield with tag 1 returns for every cell. thats why you are getting tag 1 for every textfield. Try to call the below method from your cellForRowAtIndexPath: method
- (UITextField *)createInformationTextField:(NSString *)createInformationTextField createInformationPlaceholder:(NSString *)createInformationPlaceholder index:(NSIndexPath*)indexPath
{
UITextField *informationTextField = [[UITextField alloc] initWithFrame:CGRectMake(120, 12, 170, 30)];
informationTextField.autocapitalizationType = UITextAutocapitalizationTypeWords;
informationTextField.autocorrectionType = UITextAutocorrectionTypeNo;
informationTextField.placeholder = createInformationPlaceholder;
informationTextField.text = createInformationTextField;
informationTextField.adjustsFontSizeToFitWidth = YES;
informationTextField.clearButtonMode = UITextFieldViewModeAlways;
informationTextField.tag = indexPath.row;
return informationTextField;
}
set your tag to your text field in your for loop like this.
nameTxtFld.tag = 0;
addressTxtFld.tag = 1;
I have a button on my tableview cell.
But after scrolling the buttons look like this:
It looks like there is sometimes one button above the other.
How can I solve this problem?
That's my code for the button in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Chapter *chapter = nil ;
UITableViewCell *cell = nil;
NSUInteger row = [indexPath row];
switch (indexPath.section) {
case 0:
chapter = [[einfuerung objectAtIndex:row]retain];
break;
case 1:
chapter = [[vertiefung objectAtIndex:row]retain];
break;
case 2:
chapter = [[spezial objectAtIndex:row]retain];
break;
}
if ([self filesFromFolderWithChapter:chapter] > 1)
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:SimpleTableIdentifier] autorelease];
}
}
else {
static NSString *ButtonTableIdentifier = #"ButtonTableIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier: ButtonTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ButtonTableIdentifier] autorelease];
}
}
NSString *firstString;
NSString *lastString;
switch (indexPath.section) {
case 0:
chapter = [[einfuerung objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
case 1:
chapter = [[vertiefung objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
case 2:
chapter = [[spezial objectAtIndex:row]retain];
[dataInstance extractFromString: [chapter title]: &firstString: &lastString];
cell.textLabel.text = firstString;
cell.detailTextLabel.text = lastString;
cell.backgroundColor = [UIColor whiteColor];
break;
}
if ([self filesFromFolderWithChapter:chapter] > 1)
{
//VersionButton *button = [VersionButton buttonWithType:UIButtonTypeRoundedRect];
VersionButton *button = [[VersionButton alloc]initWithFrame:CGRectMake(500, 15, 150, 30) andTitle:#"ältere Versionen"];
button.chapter = chapter;
[button addTarget:self action:#selector(versionTapped:)
forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
[button release];
}
[chapter release];
return cell;
}
First of all it would be helpful to see your entire cellForRowAtIndexPath function.
It looks like you are not accounting for cell reuse correctly. You should only add a button to your cell if you are creating a cell from scratch and not if a cell is being reused. If a cell is being reused you should have a way to access the button it already has and make any changes necessary to it.
are you calling setNeedsDisplay somewhere else that would cause it to call the drawRect?