Issue with setting icon image in cell - objective-c

I am trying to create a 'blank_star icon' in every cell of a table view, the star should become a 'solid' star after the user clicks on it.
I have created a subclass of UIButton as seen below
//.h file
#interface Bleh : UIButton {
}
+(id)specialInit;
-(void)vvv;
#end
//.m file
#implementation Bleh
+(id) specialInit
{
Bleh* button=[super buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:#"blank_star.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"star.png"] forState:UIControlStateDisabled];
[button addTarget:button action:#selector(vvv) forControlEvents:UIControlEventTouchUpInside];
NSLog(#"%d",[button isEnabled]);
return button;
}
-(void)vvv
{
NSLog(#"button tapped");
[self setEnabled:false];
}
#end
I added the subclass of UIButton in my table view's cellforRow: method as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
int row = indexPath.row;
NSString *cc = [array objectAtIndex:row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
Bleh *button = [Bleh specialInit];
button.frame = CGRectMake(0, 0, 100, 100);
NSLog(#"Button:%# at row number: %i",button, indexPath.row);
cell.textLabel.text = cc;
[cell.contentView addSubview:button];
}
return cell;
}
However I am getting an issue when running the app. For instance, if I click on the cell marked 'a', the star becomes solid as expected.
The strange thing is that after scrolling down, I see some other cells with the solid star as well (see cell 'e').
Can anyone help to explain why this is happening? It seems like the state of the cell is being re-used in other cells. How can I avoid this happening?

You can store the state of the button in a NSMutableArray and when you draw the cell you set if it is enabled or disabled based on the NSMutableArray. To change the value on the Array you should Tag the cell and make the change on your vvv selector.
//.h file
#interface Bleh : UIButton {
NSMutableArray *data;
}
On your function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// Configure the cell...
Bleh *button = [Bleh specialInit];
[button setTag:row] // row is the id of the button
if([data objectAtIndex:row] isEqualToString:#"ENABLED"]) [button setEnabled:TRUE];
else [button setEnabled:FALSE];
...
}
On your vvv selector
-(void)vvv:(id)sender {
if([sender isEnabled]) {
[sender setEnabled:FALSE];
[data replaceObjectAtIndex:[sender tag] withObject:#"DISABLED"];
}
else {
[sender setEnabled:TRUE];
[data replaceObjectAtIndex:[sender tag] withObject:#"ENABLED"];
}
}
And you should init the array on your viewDidLoad, lets say for 10 cells
- (void)viewDidLoad
{
...
data = [[NSMutableArray alloc] initWithCapacity:10];
for ( int i = 0; i < 10; i++ ) {
[data addObject:#"ENABLED"];
}
...
}

Cells ARE re-used. I had this problem once myself too.
This might be a bit more memory intensive as it doesn't delete old cells from memory, but it does make coding simpler.
One trick is to do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
NSString *CellIdentifier = [NSString stringWithFormat#"Cell %i", row];
NSString *cc = [array objectAtIndex:row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
Bleh *button = [Bleh specialInit];
button.frame = CGRectMake(0, 0, 100, 100);
NSLog(#"Button:%# at row number: %i",button, indexPath.row);
cell.textLabel.text = cc;
[cell.contentView addSubview:button];
}

Related

UIButton subview in UITableViewCell doesn't hide as expected

My recent frustration is a UIButton subview in each UITableViewCell of my UITableView which I want to setHidden: according to a specific clause for each indexPath. My code is pretty much the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[self initCell:cell forIndexPath:indexPath];
}
[self updateCell:cell forIndexPath:indexPath];
return cell;
}
and the init and update methods are the following:
- (void)initCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
...
UIButton *btnMy = [UIButton buttonWithType:UIButtonTypeCustom];
btnMy.tag = kButtonMyTag;
[btnMy setFrame:CGRectMake(170, 45, 100, 30)];
[btnMy setBackgroundImage:[UIImage imageNamed:#"btn_image"] forState:UIControlStateNormal];
btnMy.adjustsImageWhenHighlighted = YES;
[btnMy setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btnMy.titleLabel.font = [UIFont fontWithName:#"MyFont" size:14];
[btnMy addTarget:self action:#selector(btnMyPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:btnMy];
UIImageView *imgViewAccessory = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"table_accessory"]];
cell.accessoryView = imgViewAccessory;
[imgViewAccessory release];
}
- (void)updateCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
UIButton *btnMy = (UIButton *)[cell viewWithTag:kButtonMyTag];
MyObject *object = (MyObject *)[self.dataSource objectAtIndex:indexPath.row];
if(object.meetsCondition)
{
btnMy.hidden = NO;
}
else
{
btnMy.hidden = YES;
}
...
}
The frustrating result is that when scrolling the button shows and hides randomly and not as expected according the if clause in the updateCell method.
Any help would be much appreciated. Thanks in advance!
You should make custom cell and depending upon the condition show and hide the button
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *nib;
static NSString *cellIdentifier= #"cell";
UITableViewCell *theCell = [self.tblView dequeueReusableCellWithIdentifier:cellIdentifier];
if([theCell.contentView subviews]){
for(UIView *view in [theCell.contentView subviews]){
[view removeFromSuperview];
}
}
if(theCell== nil)
{
nib = [[NSBundle mainBundle] loadNibNamed:#"Your custom cell name" owner:self options:nil];
theCell = [nib objectAtIndex:0];
theCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
UIButton *btn=(UIButton*)[theCell.contentView viewWithTag:101];
if(yourcondition)
//hide button
else
//show button
}
This will do
Use this code in your CellForRowAtIndexPath Also.
MyObject *object = (MyObject *)[self.dataSource objectAtIndex:indexPath.row];
if(object.meetsCondition) {
btnMy.hidden = NO;
}
else {
btnMy.hidden = YES;
}

how to create dynamic TableCells for Tableview in ios

What I want to achieve is something like this. its kind of Facebook or twitter functionality where you have a tableview in which you have a Thread and the thread contains different number of articles. the number of articles varies in each row. So basically Its like i'm sending a post on facebook and people respond to that post and those posts are added under that particular Thread(I'm just concern about the How to display it every thing else is been taken care).here is the picture
I know how to create cell and all but I don't know how to set its size dynamically. any tutorial or any piece of advise to achieve this??
Any Help is appreciated..
thanks
Perhaps this will help you. I am sending you my code, I am using a Custom Cell , which having an Emial on first index, PhoneNumber on second index and Address on third index (in your case Article). I am dynamically changing the height of Address label in CellForRowAtIndexPath ,,, and also cell height in heightForRowAtIndexPath mehthod. Here is my code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = #"FeedCell";
FeedDetailCell *cell = (FeedDetailCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell==nil) {
cell = (FeedDetailCell*)[[[NSBundle mainBundle] loadNibNamed:#"FeedDetail" owner:nil options:nil] objectAtIndex:0];
}
[tableView setSeparatorColor:[UIColor grayColor]];
switch (indexPath.section) {
case 0:
if (indexPath.row == 0) {
cell.nameLabel.text = #"Telephone";
[cell.detailLabel setText:[_feedDictionary valueForKey:#"mobile"]];
}
else {
cell.nameLabel.text = #"Mobile";
[cell.detailLabel setText:[_feedDictionary valueForKey:#"iPhone"]];
}
break;
case 1:
cell.nameLabel.text = #"E-mail";
[cell.detailLabel setText:[_feedDictionary valueForKey:#"Email"]];
break;
case 2:
cell.nameLabel.text = #"address";
[cell.detailLabel setText:[_feedDictionary valueForKey:#"address"]];
CGSize size = [[_feedDictionary valueForKey:#"address"] sizeWithFont:[UIFont systemFontOfSize:14.0]
constrainedToSize:CGSizeMake(200.0, 400.0) lineBreakMode:UILineBreakModeWordWrap];
CGRect frm = cell.detailLabel.frame;
frm.size.height = size.height;
[cell.detailLabel setFrame:frm];
default:
break;
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 2) {
NSString *address = [_feedDictionary valueForKey:#"address"];
CGSize recommendedSize = [address sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(320, INT_MAX)];
return 44 + recommendedSize.height;
}
else {
return 44;
}
}
You can use this for dynamic cell height
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath;
you can use switch cases and check indexPath.row and indexPath.section to return the required height
take a custom UITableViewCell ,
in .h file
#interface PartnerCell : UITableViewCell {
UILabel *user_name,*lbldate,*lbldesc;
LoadImage *img_trade;
UIImageView *partnerimage;
}
#property (nonatomic, strong) UILabel *user_name,*lbldate,*lbldesc;
#property (nonatomic, strong) LoadImage *img_trade;
#property (nonatomic, strong) UIImageView *partnerimage;
#end
in .m file,
#import "PartnerCell.h"
#implementation PartnerCell
#synthesize user_name,lbldate,lbldesc;
#synthesize img_trade,partnerimage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
user_name = [[UILabel alloc] initWithFrame:CGRectMake(75,8,200,15)];
[user_name setBackgroundColor:[UIColor clearColor]];
user_name.font = [UIFont fontWithName:#"Arial-BoldMT" size:15];
[user_name setTextColor:[UIColor colorWithRed:70/255.00f green:70/255.00f blue:70/255.00f alpha:1.0]];
[self addSubview:user_name];
lbldate = [[UILabel alloc] initWithFrame:CGRectMake(75,28,200,15)];
[lbldate setBackgroundColor:[UIColor clearColor]];
lbldate.font = [UIFont fontWithName:#"Arial" size:14];
[lbldate setTextColor:[UIColor darkGrayColor]];
[self addSubview:lbldate];
lbldesc = [[UILabel alloc] initWithFrame:CGRectMake(75,45,170,35)];
[lbldesc setBackgroundColor:[UIColor clearColor]];
lbldesc.font = [UIFont fontWithName:#"Arial" size:13];
lbldesc.numberOfLines = 2;
[lbldesc setTextColor:[UIColor darkGrayColor]];
[self addSubview:lbldesc];
img_trade = [[LoadImage alloc] initWithFrame:CGRectMake(3, 5, 54, 55)];
img_trade.userInteractionEnabled = YES;
[self addSubview:img_trade];
}
return self;
}
in main table view class write this code,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"%#",[[Partarray objectAtIndex:indexPath.row-1] valueForKey:#"part_id"]];
cell = (PartnerCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell=nil;
if (cell == nil)
{
cell = [[PartnerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[Partarray objectAtIndex:indexPath.row]] autorelease];
cell.selectionStyle= UITableViewCellSelectionStyleGray;
cell.backgroundColor = [UIColor clearColor];
cell.user_name.frame=CGRectMake(75,8,340,15);
cell.lbldate.frame=CGRectMake(75,28,340,15);
cell.lbldesc.frame=CGRectMake(75,45,340,35);
cell.user_name.text = #"user name";
cell.lbldate.text = #"date";
cell.lbldesc.text = #"description";
}
return cell;
}
take condition and add number of objects based on that condition.

UITableView scroll is choppy

Here is my cellForRowAtIndexPath method. Using ARC in my project.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
static NSString* cellIdentifier = #"ActivityCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
Activity* activityToShow = [self.allActivities objectAtIndex:indexPath.row];
//Cell and cell text attributes
cell.textLabel.text = [activityToShow name];
//Slowing down the list scroll, I guess...
LastWeekView* lastWeekView = [[LastWeekView alloc] initWithFrame:CGRectMake(10, 39, 120, 20)];
[lastWeekView setActivity:activityToShow];
lastWeekView.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:lastWeekView];
return cell;
}
LastWeelView allocation is slowing down the scroll i guess. In the lastWeekView, I fetch relationships of an entity from CoreData, perform a calculation on those values and draw some colors inside its drawRect method.
Here is the drawRect of LastWeekView
- (void)drawRect:(CGRect)rect
{
NSArray* activityChain = self.activity.computeChain; //fetches its relationships data
for (id item in activityChain) {
if (marking == [NSNull null])
{
[notmarkedColor set];
}
else if([(NSNumber*)marking boolValue] == YES)
{
[doneColor set];
}
else if([(NSNumber*)marking boolValue] == NO)
{
[notdoneColor set];
}
rectToFill = CGRectMake(x, y, 10, 10);
CGContextFillEllipseInRect(context, rectToFill);
x = x + dx;
}
}
What can I do to smoothen the scroll of tableView? If I have to asynchronously add this lastWeekView to each cell's contentView, how can i do it? please help.
I'd suggest allocating LastWeekView in cell's allocation scope. Also - fetch all core data objects in viewDidLoad so that in cellForRowAtIndexPath: method would retrieve it from array and not from the store. It should look something like this:
- (void)viewDidLoad
...
_activities = [Activity fetchAllInContext:managedObjectContext];
...
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCell];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
LastWeekView* lastWeekView = [[LastWeekView alloc] initWithFrame:CGRectMake(10, 39, 120, 20)];
lastWeekView.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:lastWeekView];
}
Activity *activityToShow = [_activities objectAtIndex:[indexPath row]];
LastWeekView *lastWeekView = (LastWeekView *)[[[cell contentView] subviews] lastObject];
[lastWeekView setActivity:activityToShow];
return cell;
}
Note that you may also subclass the UITableViewCell to replace contentView with your LastWeekView to quickly access the activity property.

CoreData with a CheckBox in a UITableViewCell

im trying to implement a tableview with a checkbox on each cell in wish the status(Checked/Unchecked) will get saved on a CoreData data base. i still had no success with the current implementation. If i could get some help i would be very Thankful.
The code in question:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [pictureListData count];
}
- (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];
}
// Get the core data object we need to use to populate this table cell
Compras *currentCell = [pictureListData objectAtIndex:indexPath.row];
BOOL checked = currentCell.status;
UIImage *image = (checked) ? [UIImage imageNamed:#"cb_mono_on#2x.png"] : [UIImage imageNamed:#"cb_mono_off#2x.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
[button setBackgroundImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
cell.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
[self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
Compras *currentCell = [pictureListData objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIButton *button = (UIButton *)cell.accessoryView;
UIImage *image = [UIImage imageNamed:#"cb_mono_on#2x.png"];
// patient.check is a string value set to either "Y" or "N"
// This allows the check mark to be permanently saved
if (currentCell.status) {
image = [UIImage imageNamed:#"cb_mono_off#2x.png"];
currentCell.status = NO;
}
else {
// image defaults to checked.png
image = [UIImage imageNamed:#"cb_mono_on#2x.png"];
currentCell.status = YES;
}
[button setBackgroundImage:image forState:UIControlStateNormal];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Get a reference to the table item in our data array
Compras *itemToDelete = [self.pictureListData objectAtIndex:indexPath.row];
// Delete the item in Core Data
[self.managedObjectContext deleteObject:itemToDelete];
// Remove the item from our array
[pictureListData removeObjectAtIndex:indexPath.row];
// Commit the deletion in core data
NSError *error;
if (![self.managedObjectContext save:&error])
NSLog(#"Failed to delete picture item with error: %#", [error domain]);
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
You wrote in a comment, that currentCell is a NSManagedObject.
As CoreData only can deal with objects, bool values are wrapped with in an instance of NSNumber
BOOL checked = [currentCell.status boolValue];
your code will always result in YES, as you are writing the object's address to the BOOL. and it will most likely never be 0.

Graphics in UITableView cells disappearing

Got a strange problem where I'm putting some text into a cell (using cell.textLabel) and a small "tick" graphic to the right of the cell. When I select the cell, the tick is supposed to appear, or disappear if it's already there. What actually happens is the tick appears then fades out again almost instantly. It's all pretty standard code, so if anyone's got any idea what's going on I'd be pleased to hear!
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
while ([[cell.contentView subviews] count] > 0) {
UIView *labelToClear = [[cell.contentView subviews] objectAtIndex:0];
[labelToClear removeFromSuperview];
}
}
NSString *theName = [[contacts objectForKey:[contactsKeys objectAtIndex:section]] objectAtIndex:row];
cell.textLabel = theName;
if (section == 0) {
cell.textLabel.textAlignment = UITextAlignmentCenter;
} else {
cell.textLabel.textAlignment = UITextAlignmentLeft;
}
if ([selectedContacts containsObject:theName]) {
CGFloat cellRight = tableView.frame.size.width - 70;
UIImage *theTickImage = [UIImage imageNamed:#"Tick.png"];
UIImageView *theTickImageView = [[[UIImageView alloc] initWithImage:theTickImage] autorelease];
theTickImageView.frame = CGRectMake(cellRight, 10, theTickImage.size.width, theTickImage.size.height);
[cell.contentView addSubview:theTickImageView];
}
return cell;
}
Many thanks for any help!
Well, I've figured it out - the cell.textLabel was sitting on top of my graphic, so obscuring it. I just set the backgroundColor property of the textLabel to [UIColor clearColor] and all was well - maybe I could have made my graphic sit on top of the textLabel, I haven't tried that yet.