i have a uitableview in the uiviewcontroller, i made a scrollview in the viewload event.
i am adding it to tableview's first cell. but i scroll the tableview it displays more than one scrollview after 5 cell passed.
here is the code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"customCell";
DetailCellViewController *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nibObjects =[[NSBundle mainBundle] loadNibNamed:#"DetailCellView" owner:nil options:nil];
for (id currentObject in nibObjects)
{
if ([currentObject isKindOfClass:[DetailCellViewController class]])
{
cell = (DetailCellViewController *) currentObject;
}
}
}
if (indexPath.row==0) {
[cell.contentView addSubview:scrollView];
}
else {
NSMutableDictionary *dictionary=[catData objectAtIndex:indexPath.row-1];
NSString *title =[dictionary objectForKey:#"title"]];
[cell.catTitle setText:title];
}
return cell;
}
in which event should i add & remove scrollview?
My guess is that you're getting a dequeued UITableViewCell that already contains the UIScrollView. If you really care about separating cell types, I'd recommend setting it up so that you at least have two CellIdentifier strings. (There are times where I've set up a UITableView to handle 4+ different cell types; once you go beyond one cell type, it's pretty much just more of the same.)
My suggested solution: (see explanation below code)
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"bodyCell";
static NSString *HeaderIdentifier = #"headerCell";
UITableViewCell *cell;
// I break this up into 3 sections
// #1. Try to dequeue a cell
// #2. Create a new cell (if needed)
// #3. Set up the cell I've created
// Step 1: Try to dequeue a cell
if ([indexPath section] == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:HeaderIdentifier];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
// At this point, we may or may not have a cell to use,
// so we check for the cell's value being equal to 'nil'
// and create a new cell if it is
// Step 2: Create a new cell (if needed)
if (cell == nil) {
// Again, here we check for section to determine
// what kind of cell we want
if ([indexPath section] == 0) {
// We have the "header"/first cell
// Option 1
cell = [[ScrollViewTableViewCell alloc] init];
// Option 2 (this assumes you've got a xib named
// ScrollingTableViewCell along with a class property
// named headerCell and have properly wired it up in
// Interface Builder)
[[NSBundle mainBundle] loadNibNamed:#"ScrollingTableViewCell"
owner:self
options:nil];
cell = [self headerCell];
[self setHeaderCell:nil];
} else {
// We have a "body" cell (anything other than the first cell)
// Option 1
cell = [[BodyTableViewCell alloc] init];
// Option 2 (again, assuming you've set things up properly)
[[NSBundle mainBundle] loadNibNamed:#"BodyTableViewCell"
owner:self
options:nil];
cell = [self bodyCell];
[self setBodyCell:nil];
}
}
// At this point, whether dequeued or created
// new, 'cell' should be populated
// Again, we check for section and set up the cell as appropriate
if ([indexPath section] == 0) {
// Set up the header (UIScrollView) cell as appropriate
// This is where you would add the UISCrollView to your cell
// (if you haven't set up the UIScrollView through Interface Builder)
} else {
// Set up the "body" cell as appropriate
}
return cell;
}
NOTE: I HIGHLY recommend using Option 2 above. By far, the best results I've found when using custom/non-standard UITableViewCells is to make my own UITableViewCell subclass and xib to go along with it. Here are the steps for that:
Create a subclass of UITableViewCell (we'll call yours ScrollingTableViewCell.h/.m)
Class forward/import ScrollingTableViewCell into your UITableViewController (or UIViewController that's hosting a UITableView).
Create a class property of type ScrollingTableViewCell (we'll call yours ScrollingCell).
Create a View (New File > User Interface > View) (we'll call yours ScrollingTableViewCell.xib).
Delete the stock view item in the xib and replace it with a UITableViewCell item.
Alternative #4/5
Create an empty Xib.
Add a UITableViewCell item.
VERY IMPORTANT
In the xib, the File's Owner is the ViewController, NOT the UITableViewCell. The cell's class is ScrollingTableViewCell.
In IB, connect the ViewController's ScrollingCell property to the UITableViewCell item.
If you follow the above instructions, you should be able to allocate your cell using Option 2 above and then you can set up your cell in ScrollingTableViewCell.h/.m.
Related
I have a UITableView which contains so many rows.In my screen there can be UISwitch added for few rows in UITableView.Please tell me how can i do this?
Should i create a custom cell with a UISwitch & show or hide the UISwitch.
Should i add the UISwitch directly from the code in cellForRowAtIndexPath:.
Any suggestions please?
EDIT:
I have tried this code but this does not work.
SettingsCell *cell;
static NSString *CellIdentifier = #"SettingCell";
if (cell == nil)
{
cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleDefault];
[tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
}
if(indexPath.row==2 || indexPath.row==3)
{
cell.switch_value.hidden=false;
}
else
{
cell.switch_value.hidden=true;
}
cell.label_text.text = [VALUES objectAtIndex:indexPath.row];
return cell;
If you are creating a new cell then you should use that cell for only required rows. For rest of the rows you should not take pain of hiding the switch.
If you create UISwitch directly from the code in CellForRowAtIndexPath, then you should take care while re-using the cell. If you use different identifier for both cell types, the show/hide problem will get resolved.
Both solutions work here : you can add an UISwitch in a UITableViewCell in cellForRowAtIndexPath: : be just careful to check that no previously created UISwitch exists before creating a new one.
The second solution consists in using a custom UITableViewCell subclass.
I prefer this solution because you don't have to cast your subviews or use viewWithTag: method, or even to check if your custom subview was already created.
You should create some simples subclasses, such as PickerCell, SwitchCell, TextFieldcell : thus you will have your own set of custom UITableViewCell subclasses ready to be used within all your projects.
Assuming you have registered your reuse identifier, try this :=
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SettingCellIdentifier = #"SettingCell";
static NSString *StandardCellIdentifier = #"StandardCell";
if (indexPath.row == 2 || indexPath.row == 3) {
SettingsCell *cell = (SettingsCell *)[tableView dequeueReusableCellWithIdentifier:SettingCellIdentifier forIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleDefault];
[tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
cell.label_text.text = [VALUES objectAtIndex:indexPath.row];
// Do whatever you want with the switch here
return cell;
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:StandardCellIdentifier forIndexPath:indexPath];
// instantiate a regular UITableViewCell
cell.label_text.text = [VALUES objectAtIndex:indexPath.row];
return cell;
}
}
I have a UITableView filled with cells from a NIB-based subclass of UITableViewCell. I obtain each one like this:
+(id) getClassObjectFromNib:(NSString*) nibName subclassOf: (Class) cls owner:(id)own
{
id result = nil;
NSArray* topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:nibName
owner:own
options:nil];
for ( id currentObject in topLevelObjects )
{
if ([currentObject isKindOfClass:cls])
{
result = currentObject;
[result retain];
break;
}
}
return result;
}
My call looks like:
#interface TargetViewController : UITableViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [TargetCell defaultReuseIdentifier];
TargetCell* cell = (TargetCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = (TargetCell*) [UtilityHelper getClassObjectFromNib:CellIdentifier subclassOf:[UITableViewCell class] owner:self];
}
if ( nil != cell )
{
// Other initialization code for cell controls
cell.showsReorderControl = 1;
}
return cell;
}
But 'dealloc' never gets called on the cells when their view unloads. If I remove the 'retain' above, dealloc gets called, but the app crashes when a cell is deleted individually (via swipe) from the UITableView (crash due to message to deleted item).
Except for the single deletion case, releasing the items occurs property when the view unloads. The crash is "-[TargetCell _setDeleteAnimationInProgress:]: message sent to deallocated instance".
I discovered the problem was due to reloading the table view as part of the row deletion operation (in commitEditingStyle).
[self.tableView reloadData];
This appears to work for standard UITableViewCells but does not work when the cell is a subclass loaded from an XIB. Now I just alter the data source, delete the row (using deleteRowsAtIndexPaths) and return.
I'm newbie in IOS and again i face another issue. How can i prevent data vanish from a table cell when i scroll a tableview.
I'm using the code below to load data on the table...Works fine but the data disappear when table cell go in not visible to the screen.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
list = [self.listas objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"drop";
item_drop *cell = (item_drop*) [tabela_listas dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"item_drop" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.texto_drop.text = list.nome_lista;
return cell;
}
In android i used a holder to do it. There is anything similiar on IOS?
Since you are using reusable cells of a custom subclass of UITableViewCell, make sure you register the cell identifier in the UITableView, associating it to your custom cell type. i.e:
[yourTableView registerClass:[item_drop class] forCellReuseIdentifier:#"drop"];
You typically do this when you configure subviews in the UIViewController that controls the view your UITableView is a part of, in viewDidLoad.
With that in place, you should never hit the code inside if (cell == nil).
I have a problem with my cell textfield values when scrolling on a UITableView. When I scroll down and hide a custom cell, the value of the textField is deleted. The dequeueReusableCellWithIdentifier method doesn't work. I have this:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SectionsTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = (MyCustomCell *) [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil) {
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil];
cell = [objects objectAtIndex:0];
}
cell.labelCustomAttribute.text= #"Attribute Name";
cell.textFieldCustomAttribute.delegate = self;
return cell;
}
I find it easier to register the custom cell with the tableView in the viewDidLoad method and then simply use dequeueReusableCellWithIdentifier. If you register the cell, the dequeue method will automatically pick up a reusable cell OR allocate a new custom cell (if none is available).
Example:
-(void)viewDidLoad
{
[super viewDidLoad];
// Get a point to the customized table view cell for MyCustomCell
UINib *myCustomCellNib = [UINib nibWithNibName:#"MyCustomCell" bundle:nil];
// Register the MyCustomCell with tableview
[[self tableView] registerNib:myCustomCellNib forCellReuseIdentifier:#"MyCustomCell"];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SectionsTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
cell.labelCustomAttribute.text= #"Attribute Name";
cell.textFieldCustomAttribute.delegate = self;
return cell;
}
Normally the reuseIdentifier is assigned in the UITableViewCell's initWithStyle:reuseIdentifier: method, which you are not using because you are loading your view from a Nib.
You cannot set this property after because it is read only.
Maybe you can try instanciating the cell using the standard initWithStyle:reuseIdentifier: and add the view from your Nib as a subview of the cell's ContentView...
Now what is happening in your case is that you create a new cell every time that the Table View needs to display one. Clearly, this is not going to work. Actually, if you were reusing cells, you would have to also store the content of your text field somewhere (preferably in your data source) and put it when you reuse the cell. If you do not store it, when the cell is going to be reused, it will contain the data from the previous row in which it was displayed.
I am trying to create a "settings" table view for my app. I am trying to mimic it to be the same style as the gneral setting on an Iphone. I have created my own custom cell class by inheriting from UITableCell. I gave it the appropriate IBOulets and i have hooked them up in the storyboard. I also hooked up the switch to my tableViewControler, but for some reason my code is only returning me one empty cell (it being only one cell is not an issue atm for that's all i have in my setting). I triple checked and made sure that I'm using the same cell identifier in my code and in storyboard. Anyone know why I'm getting a blank cell back?
Here is my .h file for my custom cell.
#interface NHPSettingsCell : UITableViewCell
#property (nonatomic,weak) IBOutlet UILabel *settingLabel;
#property (nonatomic,strong) IBOutlet UISwitch *settingSwitch;
#end
MY Problem code is here, my .h file for the custom cell:
#import "NHPSettingsCell.h"
#implementation NHPSettingsCell
#synthesize settingLabel, settingSwitch;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
My method for drawing the cell in my custom view controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SettingsCell";
NHPSettingsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[NHPSettingsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellStyleDefault;
}
cell.settingLabel.text = #"firstSetting";
//check the if user wants promt of disclaimer each time or not.
if([prefs boolForKey:#"firstSetting"] == YES){
cell.settingSwitch.on = YES;
}else{
cell.settingSwitch.on = NO;
}
return cell;
}
Now the thing that annoys me is i have successfully managed to implement the cellForRowAtIndexPath method for a dynamic table that uses custom cells. I have also implements the code for a static table using the default cell, but for a static table with custom cells it just doesn't seem to work. Here is the code on how I implemented my custom cells on a dynamic table (note how i didn't have to init the cells but it works).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"InteractionResultCell";
NHPResultCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure & Fill the cell
cell.leftLabel.text = [[resultsList objectAtIndex:indexPath.row] substanceName];
cell.rightLabel.text = [[resultsList objectAtIndex:indexPath.row] substanceName2];
NSString *color = [NSString stringWithFormat:#"%#", [[resultsList objectAtIndex:indexPath.row] color]];
//Change a hex value to a readable 0x number to pass ot hte macro so we can go from a hex color to a RGB system.
NSScanner *scanner;
unsigned int tempint=0;
scanner = [NSScanner scannerWithString:color];
[scanner scanHexInt:&tempint];
cell.severityButton.backgroundColor = UIColorFromRGB(tempint);
return cell;
}
Two problems:
If you are using static cells, do not implement any datasource methods in your view controller (numberOfRows, numberOfSections, cellForRow...) as this will override what you have built in the storyboard. The table has the sections, rows and content you give it in the storyboard.
Cells loaded from the storyboard (either dynamic prototypes, or static cells) are initialised using initWithCoder:, not initWithStyle:. awakeFromNib: is a better place to put your set up code.
dequeueReusableCellWithIdentifier: works only if a cell has already been created to prevent repeated memory allocations. You cannot reuse a cell without creating it first. The static cells created in the xib are the default type. That's why it doesn't work for static table with custom cells. Add the cell creation code after reuse as you've done in your custom view controller's cellForRowAtIndexPath: method:
if (cell == nil) {
cell = [[NHPSettingsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellStyleDefault;
}
EDIT- To init your custom cell, you'll have to load from xib. Add the following class method to your NHPSettingsCell.m:
+(NHPSettingsCell*) createTextRowWithOwner:(NSObject*)owner{
NSArray* wired = [[NSBundle mainBundle] loadNibNamed:#"NHPSettingsCell" owner:owner options:nil];
NHPSettingsCell* cell = (NHPSettingsCell*)[wired firstObjectWithClass:[NHPSettingsCell class]];
return cell;
}
and then call it from your custom view controller as:
cell = (NHPSettingsCell*)[tableView dequeueReusableCellWithIdentifier: CellIdentifier];
if (Nil == cell) {
cell = [NHPSettingsCell createTextRowWithOwner:self];
}