I have collection view with 3 cells. Each cell contains one button. When I tap on the button in the first cell it starts animate itself. So my gaol is to dismiss animation in the current button if I tap for example on the button in the second/3rd cell and vice verse.
What is the better way to do it. I suppose to store maybe all buttons in some array and then check which one is active now and then switch off it and switch on other.
But maybe it's better to create some cell builder or smth like that.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(VAXSettingsModeCell.reusableCellIdentifier(), forIndexPath: indexPath) as! VAXSettingsModeCell
cell.delegate = self
let title = modesStrings[indexPath.row]
cell.AnimatableButton.setTitle(title, forState: UIControlState.Normal)
}
You can store IndexPath of animated cell inside your ViewController
#interface MyViewController: ViewController
#property (strong, nonatomic) NSIndexPath *animatedCellIndexPath;
#end
When user tap the button inside cell you can save this cell's indexPath and stop animations for all visible cells and then start animation for tapped cell.
- (void)buttonTappedForCell:(UICollectionViewCell *)tappedCell {
self.animatedCellIndexPath = [self.collectionView indexPathForCell:tappedCell];
for (UITableViewCell *cell in [self.collectionView visibleCells]) {
[cell setAnimating:NO];
}
[tappedCell setAnimating:YES];
}
And for every new cell you can check if that cell must be animated (for example if user scrolls collection view)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
cell = ...
[cell setAnimating:indexPath == self.animatedCellIndexPath];
return cell;
}
Create UICollectionViewCell reference on the animating cell and when you press on other cells (didSelectCell..) stop the animation on that cell. When you animating other cell change the reference to the animating cell. Have in mind that if you are using reuseIdentifier and the animating cell is not showing in the screen then the UICollectionView will reuse it and you might see the animating cell on the wrong position. In that case your solution with array will be the ideal but you have to track that the animating cell is not showing in the screen (or in the cellForRowAtIndexPath stop the animation on each cell and then check if the currentIndex path has to animate and start animating).
Update
You can do it without array. Just set an NSInteger activeCellIndex=indexPath.row and check that one.
Related
Is there a way when I touch the point which out of tableview frame,invoke tableview delegate function -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath?
I've tried override superview of tableview's -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event and change the point and let the event continue pass to the tableview and tableview's subviews.Just scroll event work but click event.
Here is a demo project
Problem is what UITableView don't keep all cells alive. Cells are reusable. Just several cells before and after visible area placed on view.
Try to call the delegate method directly.
tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
If you want to call this method only for cells currently available on a table view.
if let _ = tableView.cellForRow(at: indexPath) {
tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
}
You could easily convert the screen position into the index of the cell.
We have a UITableView, every row as a UICollectionView that supports an horizontal scroll, without paging enabled.
We has the cells registered for reuse,
// Setup for VenueFilterTableViewCell
NSString * cellIdentifier = #"VenueFilterTableViewCell";
VenueFilterTableViewCell *tbCell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (tbCell == nil) {
tbCell = [[VenueFilterTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
tbCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Method for inflate the UICollectionView in the row
[tbCell setVenues:venues
loading:NO
atLocation:self.definedLocation
forFilter:filter
withDelegate:self];
cell = tbCell;
When I scroll the row horizontally the UICollectionView at the indexPath.row 0 in the UITableViewCell, the indexPath.row 3 (initially out of the screen) scroll at the same time. So, if after scroll horizontal, you move scroll down quickly you can see the row 3, and the row 7... and so on, scrolling at the same time.
I have a progress bar in each cell, for providing feedback to the user how far to the end of the horizontal scroll he is, but because of this reuse behaviour, each row involved (0 and 3 and 7) is messing up the progress of the other.
Any suggestions?
UPDATE
I added into the UITableView the next event for controlling when the cell is out of the screen and force the UICollectionView inside to stop scrolling. That enhanced a bit the performance, but eventually the issue happen again.
Code in the UITableViewController for detecting when the row is out of the screen:
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if ([tableView.indexPathsForVisibleRows indexOfObject:indexPath] == NSNotFound) {
// This indeed is an indexPath no longer visible
// Do something to this non-visible cell...
if ([cell isKindOfClass:[VenueFilterTableViewCell class]]) {
VenueFilterTableViewCell *tbCell = (VenueFilterTableViewCell *) cell;
[tbCell stopScrolling];
}
}
}
Code in the UITableViewCell with the UICollection View, in the reload content, apart from recovering the contentOffset, we need to re-enable the self.collectionView.scrollEnabled = YES;
- (void) stopScrolling {
self.collectionView.scrollEnabled = NO;
[self.collectionView setContentOffset:self.collectionView.contentOffset animated:NO];
}
My first answer was not helpful. so I have fixed in this one Sorry to put it in swift you can easily convert that in objc
I have implemented willDisplayCell and endDispayCell with following code
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ScreenShotsCell else { return }
self.configureCell(for: indexPath, to: cell)
cell.collectionView.setContentOffset(cell.collectionView.contentOffset, animated: true)
cell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
//--------------------------------------------------------------------------------
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ScreenShotsCell else { return }
storedOffsets[indexPath.row] = cell.collectionViewOffset
cell.collectionView.setContentOffset(cell.collectionView.contentOffset, animated: true)
}
Main core logic is cell.collectionView.setContentOffset so it will stop scroll when it is not visible so it will fix the issue of other row's of tableview scrolling because of reuse cell
Hope it is helpful
Seems like a typical issue caused by cell reusing. If you really have a UICollectionView as a part of a cell, the best way is to create a Dictionary of stored offsets.
Quick example:
var storedOffsets: [Int: CGFloat] = [:]
in tableView:didEndDisplaying:forRowAt: store the offsets of a collectionView's contentOffset.
and
then in tableView:willDisplay:forRowAt: use these stored offsets to set the contentOffset of the collectionView in the cell.
I have a tableView which contains a label, image and UIVIew with a red background colour.
This is a picture of a row in my tableView which displays a label, image and a UIView that has a red background colour
But whenever I select a cell, the background colour of the UIVIew disappears and all I can see is the label and image
This is the same row when I select it
I was wondering if there was a way to stop the background colour of the view from disappearing whenever the cell is selected.
It is happening because cell selection style is set to default, change the UITableViewCell selection style to none.
Objective C:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
Swift 3:
cell.selectionStyle = .none
If you want to notify user has selected the cell, Maintain a property of NSArray which contains list of indexpath object.
Update the NSArray on delegate method didSelectRowAtIndexPath method.
In cellForRowAtIndexPath method change background color if indexpath exists in NSArray
Finally on didSelectRowAtIndexPath reload the selected row.
Try this:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Just add this below line didSelectRowAt
tableView.deselectRow(at: indexPath, animated: true)
}
It's a little better. I extracted from MBProgressHUD/Demo
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
});
}
I want to be able to change the color of a single UITableView cell. In my tableView(editActionsForRowAtIndexPath) I can swipe the cell and select a button to change the background color but when I scroll the cell off screen it changes back. How do I get it to retain the color? Thanks
Assuming you have only one section in your tableView with many rows, you need to do this in your tableView:cellForRowAtIndexPath: method:
if (indexPath.row == coloredCellIndex) {
cell.backgroundColor = UIColor.RedColor()
} else {
cell.backgroundColor = UIColor.WhiteColor()
}
You need to set the variable coloredCellIndex anywhere outside of this function, for example in viewDidLoad
Sorry, I can only write my answer in Objective-C. But I hope you can get my point.
If you are using a custom prototype cell, then you can add a property to your custom table view cell class, and store the current color you want for that cell, and then later in reload that color.
Sample code:
In CustomTableViewCell.h
#interface CustomTableViewCell : UITableViewCell
#property (nonatomic) UIColor *cellColor;
- (void)reloadBackgroundColor
#end
In CustomTableViewCell.m
- (void)reloadBackgroundColor
{
self.backgroundColor = cellColor; //this is just a sample.
}
And then under you can just set that color everytime the cell is reloaded.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CustomTableViewCell *tableCell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomTableCellIdentifier"];
[tableCell reloadBackgroundColor];
return tableCell;
Now, everytime you scroll the table, the color you want to set to that cell will be loaded.
If you are not using a custom prototype cell, then I suggest that you store the color you want for each cell in a Dictionary, with its index as the key. Then you just assign it again to that cell every time it is reloaded.
I hope this helps you. :)
Swift 3
viewDidLoad
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
cellForRowAt
cell.backgroundColor = .black
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "myCell") as! CustomTableViewCell
cell.accessoryType = .none
cell.backgroundColor = .black
return cell
}
This is a simple question that I thought would have an easy-to-find answer but didn't. I want to select a cell in a collectionview. The main problem is that I can't attach a gesture recognizer to a prototype cell. I want to grab the text from a label on the cell that is touched. I use the name in a different function in my view.
Or a simpler question: Is there a tutorial on tap selection from a list of items?
You have the method collectionView:didSelectItemAtIndexPath: in the delegate. This should fire when you collect the cell and give you the correct indexPath for that particular cell.
Use this indexPath in combination with the collectionView's cellForItemAtIndexPath: to access a particular cell.
Example:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self manipulateCellAtIndexPath:indexPath];
}
-(void) manipulateCellAtIndexPath:(NSIndexPath*)indexPath {
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
// Now do what you want...
}
And, as long as I'm here. Swift-version:
override func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
manipulateCellAtIndexPath(indexPath)
}
func manipulateCellAtIndexPath(indexPath: NSIndexPath) {
if let cell = collectionView?.cellForItemAtIndexPath(indexPath) {
// manipulate cell
}
}