I have a UICollectionView inside of a normal UIViewController.
Inside the collectionview I have designed the reusable UI for the collectionviewcells in storyboard.
Inside of the collectionviewcell there is a label that displays the cells indexpath.row and 5 UIButtons which if selected, change color and stay selected.
I have set up the collectionview so that if more that 30 cells are requested the collectionview will page horizontally, the collectionview layout is also horizontal.
The application runs nicely, scrolls properly and lays out cells correctly.
The problem I am having is when you select for example button A in cell 1 in the collectionviewcell (which is suppose to layout 100 cells) and page over two pages (60+ Cells) to page 3, button A in cell number 75 is selected. And further more if you scroll to the end (100 cells) and scroll back to page 3, button A in cell number 75 is on longer selected, but button A in cell number 64 is selected.
Here is some snippets of code:
cell.m - controls the action from the user.
- (IBAction)bubbleButtons:(id)sender {
for(UIButton *bubbleCell in self.bubbleButtons) {
if (bubbleCell.touchInside && !bubbleCell.selected) {
bubbleCell.selected = YES;
} else if (bubbleCell.touchInside && bubbleCell.selected) {
bubbleCell.selected = NO;
}
}
}
MainViewContoller.m - sets up cell from UICollectionViewCell made in storyboard
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Cell *cell1;
cell1 =[collectionView dequeueReusableCellWithReuseIdentifier:zCellID
forIndexPath:indexPath];
cell1.numMainLabel.text = [NSString stringWithFormat:#"%d |",indexPath.row+1];
return cell1;
I do not really understand what is wrong or what is causing this bug, I am assuming it has todo with the view being reloaded when a new part of the view becomes visible but that is just a guess. Help would be greatly appreciated.
Zach
It's probably because the reusable view is reused.
The proper way to do this is to create custom reusable view subclass.
And save the selection of those 5 button.
cell1 =[collectionView dequeueReusableCellWithReuseIdentifier:zCellID
This line here might or might not give you a new cell, it might give you a cell that is used before. So, you need to update the selection in there. Or it stay the same as the cell it's reusing.
The Uicollection only generate the cells that are been displayed at that moment, so when a cell disapier from the visible view, its been replace with the new one.
So when you seleted the cell 75 and you scroll down, until the cell 75 is no visible, and then you scroll back to cell 75, you are generating a new cell, with a new button that is not seleted because is new.
So what yo could do, is save which buttons had been selet, and in
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
ask if the button thats is been displayed at that moment need to be selected..
Hope its helps
Related
So I've made some custom table view cells and they draw correctly and look great, however once I scroll past the edge of the visible cells they start being reused, which is fine, except that when I scroll back the reused cells are still shown and don't redraw. Specifically all the cells look the same except for the top-most cell.
Pictures detailing the occurrence:
How I have this coded up, is when the cells get made if the indexPath.row is greater than 0 add an "overlap effect" which is just a gradient on a uiview placed underneath the custom drawing on the UITableViewCell's contentView.
This is how I add the overlap effect in the UITableViewController's tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"APostCell";
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
CustomPost *aPost = [self.posts objectAtIndex:indexPath.row];
if (indexPath.row > 0) {
[cell addOverlap];
}
cell.postDateLabel.text = [aPost datePostedAsString];
return cell;
}
How would I implement this [cell removeOverlap]?
Try this
if (indexPath.row == 0) {
//remove overlap here
} else {
[cell addOverlap];
}
beacuse, except 1st cell all have overlap.On scrolling the reused cell have the overlap. So for first cell remove the overlap if present.
So after I posted the question I figured it out and, since I had the question and had previously not found any information on the subject figured I would share.
So whenever
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]
is called, the table view either creates a new cell or reuses an old one. When a new cell is created and it is not the top cell (indexPath.row == 0) it adds the overlap to the UITableViewCell. And if it reuses the cell, that method still gets called, regardless what cell is being reused. So naturally once the cell created at the top is reused, the gradient view still gets added to cell.contentView and it stays there even when I'm reusing for the topmost cell again.
In fact adding the overlap view in this way will stack multiple overlap views into the same cell.
So what has to be done (if you intend to customize the cell appearance this way) is to remove the added views before each reuse of the cell. So you have to overwrite the custom tableviewcell's prepareForReuse method and do just that like so.
- (void) prepareForReuse {
[super prepareForReuse];
[self removeOverlap];
}
Be SURE the cell has the overlap view otherwise your app will break by trying to remove views not there. so have something like
- (void) removeOverlap {
if ([self.contentView.subviews count] > 1) {
//This method works based on the assumption [cell addOverlap] adds new view
//underneath existing views - like [self.contentView insertSubview:overlappedView atIndex:0];
[[self.contentView.subviews objectAtIndex:0] removeFromSuperview];
}
}
Trying to be ios7-esque, I am inserting a UIPickerView into a UITableView when tapping on a cell in the table. This works fine and animates nicely. However, there is an issue when I retract the cell by calling deleteRowsAtIndexPaths.
I am experiencing a "bleed"/overlap where the picker is hiding one of the cells further down in the table view. See the screenshots.
I'm not doing anything super custom, so I wonder if this is an iOS7 bug. All cells have solid background colors (white).
Any help would be greatly appreciated. Thanks!
Tapping the top row
This is mid animation when retracting. Notice the overlap and the picker bleeding out over the cell at the bottom
I'm not sure why, but it looks to me like the picker cell is covering the cell below "Choose Product". If this is indeed the case, one workaround would be to explicitly set the z-order of your cells, placing the picker cell under all others:
#import <QuartzCore/QuartzCore.h>
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...;// your logic for getting a cell
BOOL isPickerCell = ...;// your logic for identifying if this is the picker cell
cell.layer.zPosition = isPickerCell ? 0 : 1;
}
If the picker is near the bottom of the table, it could still show through below the last cell since there's nothing there to cover it. For example, if "Choose Product" were the last cell. You can work around this by inserting blank cell(s) at the bottom. This is a general problem with having cells of varying height.
After struggling with this problem, I realised that Apple's calendar application has the same issue
However, they minimise the side effects by inserting the row with a .fade animation.
tableView.insertRows(at: indexes, with: .fade)
I had similar issues (iOS 8, iPhone 6 simulator)
In my case, I had a custom cell containing a DatePicker being inserted/deleted either between Right Detail style cells or between a Right Detail style cell and the section footer, which worked as expected.
[self.table beginUpdates];
if (isVisible) {
[self.table insertRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
} else {
[self.table deleteRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
}
[self.table endUpdates];
But I also had Right Detail style cell being inserted/deleted between a Right Detail style cell and the end of section, which did not work as expected using the same code. The appearing/disappearing cell was visible on top of/through the cell above, and the cell moved twice as far as it should have. In the image below, People is appearing below Privacy, mid-animation.
However, I noticed that when the beginUpdates/endUpdates were commented out, the cell only moved about half a cell height instead of twice a cell height which meant that it looked much improved.
I also tried setting the zPosition which appeared to lessen the visibility when the cells overlapped.
// [self.table beginUpdates];
if (isVisible) {
[self.table insertRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
} else {
cell = [self.table cellForRowAtIndexPath:peopleIndex];
cell.layer.zPosition = -1;
[self.table deleteRowsAtIndexPaths:#[peopleIndex]
withRowAnimation:UITableViewRowAnimationMiddle];
}
// [self.table endUpdates];
I have an UICollectionViewController and my custom cells, and in my cellForRowAtIndexPath: method I set the cells based on indexPath.row.
But I am getting wrong results, this cell appears even after first position, and if you scroll back and forth, it pops up in random places. How do i fix that?
Here is the code:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DVGCollectionViewCell *cell;
cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
if (indexPath.row == 0)
{
cell.imageView.image = [UIImage imageNamed:#"something1.png"];
cell.buyLabel.text = #"170";
cell.textLabel.text = #"11.2011";
}
return cell;
}
Cell in both UITableView and UICollectionView are recycled, that means that when one goes off screen it is put in an NSSet until you need it again. When it's need it's removed from the set ad added again at UICollectionView views hierarchy. If you do not clean the value inside the cell or set them again, the cell will show the same data when it was created.
This is made for performance reason creating cell takes more time instead of value them again.
If your problem is in layout check the layout flow object, which size did you set?
I have found the problem, once the cell contents was set it was never cleaned. So I added cleaning every cell properties as additional clause and it works fine.
You can perform any clean up necessary to prepare the view for use again if you override prepareForReuse in your custom cell implementation.
One of the answers in this SO post helped: override prepareForReuse and reset the cell to its default state. Don't forget to call super.prepareForReuse.
I am just starting to implement a multiselect UICollectionView. Would the below be considered "safe" code (since i assume theres some reason it is called BackgroundView instead of AccessoryView or such) ? I had the idea to save some effort, i intend to keep track of the selected items at the indexpath for further use via an array.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//....
cell.selectedBackgroundView = someView_With_A_Checkmark_Image;
[cell bringSubviewToFront:cell.selectedBackgroundView];
//...
return cell;
}
Is it safe?? Ya of course it wont cause any error. If your backgroundView is above the contentView of the cell, then what is the significance of contentView??.
Collection view cell structure
If you select an item in the collection view, collectionView will switch the BackgroundView and Selected background view. So what you can do is give valid views as background view and selected background view upon configuring your custom cell or change any properties of the cell in didSelectItem to differentiate selection. That is better.
Then one more no need to keep track of selection using a separate array. [self.collectionView indexPathsForSelectedItems] will give you selected items path at any point of time
I want a table view with only cels, and when you click on a cell it should expand and show more info of the clicked cell.
I've seen quite some topics on this, but the most of them are linking to Table View Animations and Gestures on the apple developer page. Which does it in a different way. They use header sections, but I want to use the cell which is expandable for layout reasons.
I already tried several things mainly with
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
return 110;
}
else {
return rowHeight;
}
When I Click on the cell, the cell is expanded but the info in that cell stays the same. Also the heigth of the cell when expanded should be related to the amount of text in the details.
Thnx!
You can achieve this through the use of custom cells. Create two custom cells, one for the normal row and other for the expanded row. When the user touches a particular cell, you can record it's indexPath and reload the tableView. While reloading you can change the height of this selected row using the code that you've just posted(increasing the height of only the selected cell). This would give an effect of expanding cell.