I have a table, and based on a simple boolean, I add a subview containing an image to the right side of the cell using this code in cellForRowAtIndexPath:
if(myArray[indexPath.row]==YES){
int xpos=self.mainTableView.frame.size.width+self.mainTableView.frame.origin.x-24;
int ypos=(cell.frame.size.height/2)-(18/2);
UIImageView *imv=[[UIImageView alloc]initWithFrame:CGRectMake(xpos,ypos, 18, 18)];
imv.image=[UIImage imageNamed:#"transition-30"];
[cell.contentView addSubview:imv];
}
If when the value of "myArray[x]" is NO, how can I remove the previously added subview?
I've tried using: [cell.contentView removeFromSuperview] but that removes the entire contents of the cell - text included.
You have to call removeFromSuperview on imv --> [imv removeFromSuperview];
To get the previously added imv, you could set the tag property of your imv to a constant and get it at the next call with viewWithTag (see here)
So before adding the subview:
imv.tag = 1;
[cell.contentView addSubview:imv];
When deleting the subview you first have to trigger a reload of the desired cell with
reloadRowsAtIndexPaths:(NSArray *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation;
and then in cellForRowAtIndexPath you do the following if myArray[indexPath.row] == NO
UIImageView *imv = (UIImageView*)[cell.contentView viewWithTag:1];
[imv removeFromSuperview];
Using the tag property is bad practice so consider creating your own UITableViewCell
See here for a description how to do that.
Related
I have UICollectionView with custom flow layout, which purpose is availability to delete items. In order to retrieve index i use function:
-(void)aMethod:(UIButton*)sender{
[self.viewModel deleteAt:[sender tag]];
[self.myCollectionView reloadData];
}
Sometimes (in rare cases) i got crash. When i dig into it, i found that sometimes [sender tag] was incorrect, in fact, higher then array of items count. Why is that happen? I found that it send 8, when array only had 5 items.
Button is simple 40x40 width/height image, placed above UITableViewCell like this:
UIButton *button = [UIButton new];
[button setImage:[UIImage imageNamed:#"m_delete"] forState:UIControlStateNormal];
if (self.shouldEdit){
self.layout.longPressGestureRecognizer.minimumPressDuration = 0.3f;
NSLog(#"1 blk called");
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
[button setTag:indexPath.row];
[cell addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(cell.mas_left).with.offset(2);
make.top.equalTo(cell.mas_top).with.offset(2);
}];
}
I suspect that it's reusing old cell without updating the button's tag. Since you have conditions if (self.shouldEdit) which means the [button setTag:indexPath.row]; is not always called. You mentioned that the purpose of the buttons is to delete items so it might be that the tableView reused old / deleted cell (the one with tag 8) as one of the 5 cells and it doesn't call the setTag
You can take the setTag line outside the conditional so it will always update the button's tag every time the cell is created / reused.
Alternatively you can make sure the old button are removed from cell before reuse in UITableViewCell's prepareForReuse or inside cellForRowAtIndexPath right after dequeueReusableCellWithReuseIdentifier(...). Doing this you must always add new button because the old ones are removed from the cell
button tag is override every time when cellForRowAtIndexPath callled so dont set tag in that method
remove this line
[button setTag:indexPath.row];
use this one
-(void)aMethod:(UIButton*)sender
{
CGPoint point=[sender convertPoint:CGPointZero toView:collectiewname];
NSIndexPath *indexPath=[collectiewname indexPathForItemAtPoint:point];
NSLog(#"row :%ld",(long)indexPath.row)
}
I have a UITableView in Grouped format with a few cells in it. In the cells is a UIView to which I am adding another UIView. When I update the frame of the first UIView, it doesn't change the position of it nor the size.
The UIViews realign themselves correctly if the cell goes offscreen and onscreen again, so the actual transformation is being applied, it's just the re-rendering that's not happening properly.
The code for this is just in my cellForRowAtIndexPath:
[cell.cellMoney setBackgroundColor:[UIColor clearColor]];
[cell.cellMoney.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView *sellMoneySubView = [UIMoneyDisplay createViewWithAmount:item.min_sale_unit_price fontSize:17.0];
[cell.cellMoney setFrame:CGRectMake(cell.frame.size.width-sellMoneySubView.frame.size.width-20, 7, sellMoneySubView.frame.size.width, sellMoneySubView.frame.size.height)];
[cell.cellMoney addSubview:sellMoneySubView];
[cell setNeedsLayout];
The sub UIView that I'm adding to the first UIView gets added and rendered properly, it's just the first's positioning that's gone weird.
Oh, I'm also using AutoLayout with the storyboard.
Addition: I fixed part of my problem, but the title is still valid. I also have a cell with an image that needs to be downloaded through the network, but that cell doesn't respond to any form of layout call either.
I fixed the problem with the position of the UIView by removing the middle view and adding straight to the cell's contentView.
instead of this
[cell setNeedsLayout]
use [cell layoutIfNeeded]
[cell.cellMoney setBackgroundColor:[UIColor clearColor]];
[cell.cellMoney.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIView *sellMoneySubView = [UIMoneyDisplay createViewWithAmount:item.min_sale_unit_price fontSize:17.0];
[cell.cellMoney setFrame:CGRectMake(cell.frame.size.width-sellMoneySubView.frame.size.width-20, 7, sellMoneySubView.frame.size.width, sellMoneySubView.frame.size.height)];
[cell.cellMoney addSubview:sellMoneySubView];
[cell layoutIfNeeded]; //use this
return cell;
This might helps you :)
Just getting started with UICollectionView. I've used IB to create a simple UICollectionView in a UIViewController. It scrolls horizontally with paging. I placed a simple UICollectionViewCell inside the UICollectionView. I set the reuse identifier for the cell.
I placed a UILabel with a tag of 100 inside the UICollectionViewCell.
In viewDidLoad, I call:
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Thing"];
Later I attempt to initialize the cell like so:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Thing" forIndexPath:indexPath];
cell.backgroundColor = [UIColor greenColor];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:100];
nameLabel.text = #"Bogus";
return cell;
}
When I run the app, the view loads correctly; I can scroll horizontally through the 2 cells. I see the ugly green color identifying each cell.
However, the viewWithTag method returns nil and therefore the nameLabel text is not set.
Why?
Note that I also tried defining a custom subclass of UICollectionViewCell and calling registerClass with it. In IB, I change the cell class to the custom subclass and I bind the UILabel to the UILabel outlet in the subclass.
But this also does not work. (I would prefer to avoid the custom subclass approach anyway because it does not seem necessary to define classes just to hold IBOutlets.)
I'm thinking that I'm missing something obvious here.
Similar problem described here:
Trouble accessing Image from instance of UICollectionViewCell
Remove the registerClass line. You are doing it on storyboard, so you don't need it.
try it
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:100];
Update:
You can look the cell's hierarchy and all its subview's tag :[self showAllSubView:cell] ;, can you find your label with tag 10 ?
- (void)showAllSubView:(UIView *)view
{
for (UIView * subView in [view subviews]) {
NSLog(#"%#, tag:%d", subView, subView.tag) ;
[self showAllSubView:subView] ;
}
}
I am building an app similar to iPhone photo app. I am able to show the images in a grid like view using PSUICollectionView. When I tap on a grid cell of collection view a checkbox image should appear. My problem is when I am using following code, I see that multiple random cells are being populated with check box images.
- (void)collectionView:(PSUICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath
{
NSLog(#"%# - %d", NSStringFromSelector(_cmd), indexPath.item);
ImageGridCell *cell = (ImageGridCell *)[collectionView cellForItemAtIndexPath:indexPath];
UIButton *chkboxBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[chkboxBtn setFrame:CGRectMake(60, 60, 30, 30)];
[chkboxBtn setImage:[UIImage imageNamed:#"Checkmark-iPhone.png"] forState:UIControlStateNormal];
[cell addSubview:chkboxBtn];
}
The problem is likely your custom cell has not implemented the prepareForReuse method. As a cell is reused, it may or may not have the check box, depending on if the check box was added on a previous use.
Several ways to address this. One simple way is to add a tag to the ckhboxBtn, and then remove the chkboxBton in the prepareForReuse method. E.g., when adding the check box, add the following:
[chkboxBtn setTag:100];
Then in your UICollectionViewCell class implementation, add/expand the prepareForReuse method:
-(void)prepareForReuse{
[[self viewWithTag:100] removeFromSuperview];
}
I have a UITableViewCell, it is scroll-disabled and with fixed sections and rows.
There are two sections, with 1 row in section 0, and several rows in section 1.
The tableView is for users to make some choices.
So, the first section (with only one row) is going to display the result of users' choices,
and no doubt the second section (with several rows) is for choosing.
Now I want to put an image in the cell of the only row of the first section,
and this image will change according to users' choose.
It is very easy to judge which png image should be displaying, but I have trouble update it.
I tried use the cell's imageView, and manually alloc a UIImageView or UIView there to display those images.
But all of them won't work, I mean they just keep what they are displaying at the beginning and never changes it, even if I set the view's background or its image to a new png.
I tried some method like
[myImage setNeedsDisplay] for the manually alloced view,
or
[thatCell setNeedsDiaplsy] & [self.tableView reloadData] for the imageView of that cell,
but in vain.
So I wonder how can I achieve this function that dynamically display an image in a UITableViewCell in different situations?
Thanks a lot!
_____update line_____
I'm sorry that I didn't provide my code.
and here they are.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *inOutTableCellIdentifier = #"DealTableViewIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:inOutTableCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:inOutTableCellIdentifier] autorelease];
cell.textLabel.font = [UIFont fontWithName:cMyFont size:[UIFont systemFontSize]];
cell.detailTextLabel.font = [UIFont fontWithName:cMyFont size:[UIFont smallSystemFontSize]];
// I tried using both imageView and UIView here, but won't work
if (indexPath.section == 0) {
//cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"moneyCell.png"]];
cell.backgroundColor = [UIColor cyanColor];
// cell.imageView.image = [UIImage imageNamed:#"dealDone2.png"];
self.undoneIcon = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)] autorelease];
//self.undoneIcon.image = [UIImage imageNamed:#"dealUndone2.png"];
self.undoneIcon.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dealUndone2.png"]];
[cell.contentView addSubview:self.undoneIcon];
.... // deal with other rows in section 1
return cell;
}
// and this is the method that update the image, the images are named "dealDoneX.png",
// where X is an integer from 0 to 4.
- (void)checkUndoneDegree { // here I also tried 2 ways corresponding to UIView or a cell's imageView, but neither works well.
int i = 0;
if (self._date)
i++;
if (self.moneyTextField.text)
i++;
if (self._incomingAccount)
i++;
if (self._expensingAccount)
i++;
if (_dealType != kTransferView)
if (self._type)
i++;
NSLog(#"undone degree: %d",i);
NSString *imageName = [#"dealUndone" stringByAppendingFormat:#"%d",i];
self.undoneIcon.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:imageName]];
[self.undoneIcon setNeedsDisplay];
// NSUInteger p[2] = {0,0};
// UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathWithIndexes:p length:2]];
// [cell setNeedsDisplay];
}
and everytime I update the table's data, like changing some text of some cell,
I would call [self checkUndoneDegree] and then call [self.tableView reloadData],
But the picture is never updated, at least from the screen.
I even tried to put the codes that decide which png to set in the
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
method, but it can only make the view displaying the first png, without any updating.
Thanks for helping!
Make your undoneDegree (represented by i variable in your code) an ivar of your view controller, so it is accessible in all of it's methods, also in the UITableView delegate and data source methods.
Forget about setNeedsDisplay method. Since you are using UITableView to display your content, you need to play by its rules. This means you should use reloadSections:withRowAnimation: method.
Check again if you need self.undoneIcon. I'm pretty sure that imageView property should do. That is if you really want to display an image in the cell. If you want to create some kind of progress bar by manipulating cell's background, then use backgroundView property, or just place UIProgressView in your cell. This is what I think your want to do, after looking at your code.