I am adding subview to UITableViewCell i.e
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault` reuseIdentifier:cellIdentifier];
Here _cellBackgroundView belongs to UIView.
[cell.contentView addSubview:_cellbackground];
I want to check by the help of isDescendantOfView if it contains _cellbackground, but I am getting warning.
if (![_cellbackground isDescendantOfView:[cell subviews]]) {
[cell.contentView addSubview:_cellbackground];
}
else{
[_cellbackground removeFromSuperview];
}
references Check if a subview is in a view
Please help
[cell subviews] return array , but you need to give UIView as input parameter for isDescendantOfView: method , try like this it will work
if (![_cellbackground isDescendantOfView:cell.contentView]) {
[cell.contentView addSubview:_cellbackground];
}
else {
[_cellbackground removeFromSuperview];
}
[cell subviews] should be replaced by a object of UIView
Related
in my cell data is loading but its is all messed up until i scroll down then if i scroll back everything format correctly. so when every i load listing which is uitableview data is messed up and as soon i start scrolling and scroll back up it gets in place and show correctly. please help.
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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
for(UIView *v in [cell subviews])
{
if([v isKindOfClass:[UILabel class]])
[v removeFromSuperview];
if ([v isKindOfClass:[UIImageView class]])
[v removeFromSuperview];
}
UIView *CellBGView = [[UIView alloc] initWithFrame:CGRectMake(10, 5, cell.frame.size.width-20, cell.frame.size.height-10)];
CellBGView.backgroundColor = [UIColor whiteColor];
UIImageView *divider = [[UIImageView alloc] initWithFrame:CGRectMake(CellBGView.frame.size.width-155, CellBGView.frame.size.height-140, 150, 150)];
divider.image = [UIImage imageNamed:#"icon_alpha.png"];
[CellBGView addSubview:divider];
......
return cell;
}
Here is out put when i open listing and before scrolling table
here is after scrolling everything gets in place
I have a solution for you.
First, create subclass of UITableViewCell (For example, name it DemoTableViewCell)
In initWithStyle method of DemoTableViewCell, add your images and labels to cell.
In cellForRowAtIndexPath, you don't need add or remove images and labels. Just change color or set image for them.
I'm trying to to something like apple's alarm clock, when tap the edit button, a custom view cover the custom UITableViewCell.
The code above:
// CGRect frame = [tableView rectForRowAtIndexPath:indexPath];
// CGPoint yOffset = self.tableViewBlock.contentOffset;
// CGRect newFrame = CGRectMake(frame.origin.x, (frame.origin.y - yOffset.y + 45), frame.size.width, frame.size.height);
CallBlock_Date_EditMode *viewController = [[CallBlock_Date_EditMode alloc] initWithNibName:#"CallBlock_Date_EditMode" bundle:nil];
// self.view.frame = newFrame;
// [self.view addSubview:viewController.view];
// [self addChildViewController:viewController];
UITableViewCell *cell = (UITableViewCell*)[self.tableViewBlock cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:viewController.view];
Cover the specific cell when I put in under:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Just to make sure the size is ok (although when I tap a button in that xib the app crash without even a single error).
But I want to do like apple's alarm clock (actually, mimic it), tap my edit button and my custom UITableViewCell will get cover with this xib as a view.
Maybe there is a better approach to do it?
EDIT:
My updated code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CallBlock_TableCell *cell = (CallBlock_TableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[CallBlock_TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(CallBlock_TableCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.accessoryType = self.isEditing ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
CallBlock_ByDate *callBlock = (CallBlock_ByDate*)[fetchedObjects objectAtIndex:indexPath.row];
cell.labelTime.text = callBlock.startDate;
cell.labelRepeat.text = callBlock.repeat;
cell.labelTextLabel.text = callBlock.label;
cell.switchCallBlock.on = YES;
cell.switchCallBlock.tag = (NSInteger)indexPath.row +1;
[cell.switchCallBlock addTarget:self action:#selector(handleSwitch:) forControlEvents:UIControlEventValueChanged];
cell.switchCallBlock.hidden = self.isEditing ? YES : NO;
if (self.isEditing)
{
cell.switchCallBlock.hidden = YES;
UIButton *btnArrow = [[UIButton alloc] init];
btnArrow.frame = CGRectMake(282.0, 31.0, 18.0, 21.0);
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_off"] forState:UIControlStateNormal];
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_on"] forState:UIControlStateHighlighted];
btnArrow = [UIButton buttonWithType:UIButtonTypeCustom];
[btnArrow addTarget:self action:#selector(handleTapToEdit:) forControlEvents:UIControlEventTouchUpInside];
btnArrow.tag = indexPath.row + 1;
[cell.contentView addSubview:btnArrow];
[cell.contentView bringSubviewToFront:btnArrow];
}
}
But I cannot get the btnArrow appear on the UTableView.
The reason you are getting a crash is because nothing is retaining your CallBlock_Date_EditMode view controller. You add its view to your cell as a subview, but nothing maintains a reference to the view controller, so it is deallocated and then, when pressing a button that is supposed to pass a message to your view controller, it is sent to a deallocated object and you get a crash.
There are two possible solutions to this. First, you could store that view controller in one of your properties to maintain a reference to it so that it does not deallocated. This is, for the most part, probably not what you want.
Instead, what I would suggest doing is do not make your CallBlock_Date_EditMode a UIViewController, but instead make it a UIView. You may be wondering "But how can I use a xib without a UIViewController?". I would do something like the following:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"CallBlock_Date_EditMode" owner:self options:nil] objectAtIndex:0];
self.myEditButton = (UIButton *)[view viewWithTag:2];
[self addSubview:view];
}
return self;
}
This would be code inside your custom UIView that would load in a xib file and add it as a subview. In order to get access to your subviews, you have to use tags inside interface builder, so you do lose the convenience of drawing/connecting IBOutlets... But in the end, it is much better than allocating/storing a bunch of unnecessary UIViewControllers.
If I understand you right and you want to mimic the functionality of the alarm clock that comes pre-installed from Apple, your solution is much simpler than creating a custom view. It looks like all they do is set the On-Off switches to hidden and add a disclosure indicator to the cell. This is what I would do...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
bool hide = (tableView.editingStyle == UITableViewCellEditingStyleDelete); // set to true or false depending on if the table is in editing mode
for (UIView *sv in [cell subviews] ) {
if([sv isKindOfClass:[UISwitch class]]) { // find the on-off switch
[sv setHidden:hide]; // hide the switch depending on the t/f value of hide
break;
}
}
if(hide) { // adds the arrow like in apple's alarm clock table if the cell is in edit mode
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}
I've one UITableView with 5 Sections and multiple different rows within each section.
My code for add UISwitch into TableView
switchForNotification = [[UISwitch alloc]initWithFrame:CGRectMake(300, 10, 100, 40)];
[switchForNotification addTarget:self action:#selector(Notification) forControlEvents:UIControlEventValueChanged];
switchForNotification.on = NO;
[cell.contentView addSubview:switchForNotification];
So, it'll add into TableViewCell.But, when I'm scrolling, Table is reloading accordingly with UITableView methods and switch will be added into other cells.
I want to prevent this issue of adding automatically custom controls into cell while scrolling and reloading.
How can I do that ?
Any suggestions will be appreciated.
Thanks in advance.
You can Make one custom cell which contains one UILable ,UISwitch and UIImageview...
Now as per indexpath.row show and hide this subview as per you needs.
Try this code. Add this code in your cellFotRowAtIndexPath
NSArray *subviews = [[NSArray alloc] initWithArray:cell.contentView.subviews];
for (UIView *subview in subviews)
{
if([subview isKindOfClass:[UIView class]])
[subview removeFromSuperview];
else if([subview isKindOfClass:[UIImageView class]])
[subview removeFromSuperview];
else if([subview isKindOfClass:[UILabel class]])
[subview removeFromSuperview];
else if([subview isKindOfClass:[UISwitch class]])
[subview removeFromSuperview];
}
[subviews release];
What you need to do is have several different instances of UITableViewCell depending on how many different types of table view cell you have.
Each is assigned a reuse identifier.
Then, in cellForRowAtIndexPath, depending on the section or row of indexPath, you dequeue the appropriate cell, set whatever data, and return that.
So, for example, assuming you have three types of cell for switch, image, and other, you would dequeue as follows:
static NSString *kCellReuseIdentifierSwitch = #"SwitchCell";
static NSString *kCellReuseIdentifierImage = #"ImageCell";
static NSString *kCellReuseIdentifierOther = #"OtherCell";
if (indexPath.row == 0)
{
MySwitchCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellReuseIdentifierSwitch forIndexPath:indexPath];
}
else if (indexPath.row == 1)
{
MyImageCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellReuseIdentifierImage forIndexPath:indexPath];
}
else if (indexPath.row == 2)
{
MyOtherCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellReuseIdentifierOther forIndexPath:indexPath];
}
This example assumes iOS 6 or above where cell instantiation is handled for you by the dequeue method.
if (cell==nil){cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier]; }
My UITableView is pulling data from an array. Items in this array have a property called IsSelected. I am trying to put a UIImageView in the cell contentView for each item that is selected.
The UITableView however when reusing the cell is causing my image to be reused on cells that it shouldn't. I cannot figure out for the life of me how I should be doing it differently. I have attached a screen shot showing the issue. If I keep scrolling up and down the image goes all over the place:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SchoolCellIdentifer = #"SchoolCellIdentifier";
SchoolInfoItem *item = [self.schoolsArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SchoolCellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SchoolCellIdentifer];
cell.contentView.backgroundColor = [BVColors WebDarkBlue];
}
cell.textLabel.text = item.Name;
if ([item.selected isEqualToString:#"1"])
{
cell.contentView.backgroundColor = [BVColors WebBlue];
UIImageView *selectedItemCheckMarkIcon = [[UIImageView alloc] initWithFrame:CGRectMake(300, 13, 17, 17.5)];
[selectedItemCheckMarkIcon setImage:[UIImage imageNamed:#"check-mark.png"]];
[cell.contentView addSubview:selectedItemCheckMarkIcon];
}
else
{
cell.contentView.backgroundColor = [BVColors WebDarkBlue];
}
return cell;
}
You need to make sure the UIImageView is getting removed from the cell content view. It looks like in your code when a cell gets dequeued that imageview is still in the cells view hierarchy.
Best solution is to have your cell hold onto a reference to the image view and remove it when necessary.
Take the following:
if ([item.selected isEqualToString:#"1"])
{
cell.contentView.backgroundColor = [BVColors WebBlue];
cell.myImageView = [[UIImageView alloc] initWithFrame:CGRectMake(300, 13, 17, 17.5)];
[selectedItemCheckMarkIcon setImage:[UIImage imageNamed:#"check-mark.png"]];
[cell.contentView addSubview:cell.myImageView];
}
else
{
[cell.myImageView removeFromSuperview];
cell.myImageView = nil;
cell.contentView.backgroundColor = [BVColors WebDarkBlue];
}
Note in the else case the removal of the imageview.
You keep adding a the UIImageView as a subview on the cell's contentView. This isn't removed when the table view is reusing the cell. You'll need to remove the subview if it shouldn't appear.
You should make selectedItemCheckMarkIcon a property on your UITableViewCell subclass. And then have a method in your subclass where you set the image or visibility of the image accordingly.
You could also use the accessoryView property on the UITableView and set the imageView as that:
if ([item.selected isEqualToString:#"1"]) {
cell.contentView.backgroundColor = [BVColors WebBlue];
UIImageView *selectedItemCheckMarkIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"check-mark.png"]];
cell.accessoryView = selectedItemCheckMarkIcon;
} else {
cell.accessoryView = nil;
cell.contentView.backgroundColor = [BVColors WebDarkBlue];
}
Note that you don't need to set a frame in this case because the system will automatically set the frame correctly for the accessoryView.
I am showing a image in CellImage when any cell is clicked it works fine but problem is that when a new cell is selected then previous cell image is also visible i want that when user selects on new cell previous cellImage should be hidden.
here is the code
-(IBAction)imageButtonAction:(id)sender{
CustomCell *cell = (CustomCell *) [[sender superview] superview];
UIButton *btn = (UIButton *)sender;
UIView *backimage = [[UIView alloc] initWithFrame:CGRectMake(300,0,312,105)];
backimage.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"popupj.png"]];
[backimage setUserInteractionEnabled:YES];
[cell addSubview:backimage];
}
I am calling this method on the button which is in cell i have used custom cell
You might try this, it may help you.
-(IBAction)imageButtonAction:(id)sender{
CustomCell *cell = (CustomCell *) [[sender superview] superview];
UIButton *btn = (UIButton *)sender;
for (UIView *subView in cell.contentView.subviews) {
if([subView isKindOfClass:[UIView class]]){
subView.hidden=YES;
}
}
UIView *backimage = [[UIView alloc] initWithFrame:CGRectMake(300,0,312,105)];
backimage.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"popupj.png"]];
[backimage setUserInteractionEnabled:YES];
[cell addSubview:backimage];
}
Or you can even use the block, to loop through subviews and hide them
Cheers
There is a value on a table view xib called selection, check that its value is set to single selection in your xib. Or programmatically set this property to NO:
#property(nonatomic) BOOL allowsMultipleSelection
Change the hidden value property of your previous selected cell in tableView:didSelectRowAtIndexPath:
Access the cell by using:
UITableViewCell *cell = (UITableViewCell *)[tableView cellForRowAtIndexPath:previousIndex];
cell.yourImage.hidden = YES;
In your button action you could set maintain the previousIndexPath which should be declared in the .h file . By using this previousIndexPath you can easily hide the previously loaded image:
CustomCell *cell=(CustomCell *)[yourTable cellForRowAtIndexPath:previousIndexPath];
cell.yourImage.hidden=TRUE;