UICOllectionview, scrolling to first cell that contains in its title an NSString - ios

I have a uicollectionview hosting a number of cells, each cell has a title on it.
the same collectionview can have multiple cells that have the same title.
I need to grammatically scroll the collectionview to the first occurrence of a cell which has title = user selection.
How can I achieve that?

Loop through you data source and find the first object and call then call collection views scrolltoIndexPath method.
__block NSIndexPath* indexPath = nil;
[yourDataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqualToString:title]) {
indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
*stop = YES;
}
}];
if (indexPath) {
//set the scroll position accordingly
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}

Related

Removing a specific cell from a Collection View

I'm trying to remove the first collection view cell. I'm having trouble getting the indexPath for the first item in the collection view. Here is what I've got so far.
-(void)removeFirstItemFromCollectionView
{
NSLog(#"%i", [self.hostQueue count]);
[self.collectionView performBatchUpdates:^{
NSIndexPath * firstIndexPath = [self.collectionView indexPathForCell:(CollectionViewCell *)[self.collectionView viewWithTag:0]];
NSArray *indexPaths = #[firstIndexPath];
//delete item from hostQueue
[self.hostQueue removeObjectAtIndex:0];
// Now delete the items from the collection view.
[self.collectionView deleteItemsAtIndexPaths:indexPaths];
} completion:nil];
}
I'm getting a crash with:
NSIndexPath * firstIndexPath = [self.collectionView indexPathForCell:(CollectionViewCell *)[self.collectionView viewWithTag:0]];
In my dataSource I set the cell's tag equal to the indexPath.row. I guess this doesn't work? How should I be getting the first indexPath?
Thanks.
You don't need to call indexPathForCell as you know that you want to delete the first cell - index 0. You can use the NSIndexPath class method indexPathForItem:inSection: to create the index path directly -
- (void)removeFirstItemFromCollectionView
{
NSLog(#"%i", [self.hostQueue count]);
//delete item from hostQueue
[self.hostQueue removeObjectAtIndex:0];
// Now delete the items from the collection view.
[self.collectionView deleteItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
}

How can I programatically select a tableview cell?

when I create a custom UITableviewCell I set cell.selected = YES in the UITableView delegate method tableview:cellForRowAtIndexPath, but it doesn't work.
However, when I call [tableView selectRowAtindexPath:] after [tableview reloadData], there is no problem. I am confused
Here is some code source:
-(void)setModel:(GAInterestSetModel *)model
{
_model = model;
if (model.iconURL && model.iconURL.length > 1) {
[iconView setImageWithURL:[NSURL URLWithString:model.iconURL]];
}
if (model.title && model.title.length > 1) {
titleLabel.text = model.title;
}
if (model.memberCounts) {
membersLabel.text = [NSString stringWithFormat:#"成员:%d",model.memberCounts];
}
self.selected = model.defaultChoosed;
}
instead method:
[modelsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
tempModel = (GAInterestSetModel *)obj;
if (tempModel.defaultChoosed) {
[rootTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
The selection is not a property of the cell. Calling .selected = YES does absolutely nothing because the table doesn't know about the selection.
You have to use [table selectRowAtIndexPath:...] otherwise it won't work.
Another possibility is to ignore the default selection and implement your own selection mechanism.

indexPathForCell returns nil since ios7

my app was running fine under ios6.1. tried the ios7 simulator and the following part does not work:
EditingCell *cell = (EditingCell*) [[textField superview] superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSLog(#"the section is %d and row is %d", indexPath.section, indexPath.row);
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *rowKey = [[keysForRows objectAtIndex: section] objectAtIndex: row];
It always comes:
the section is 0 and row is 0
although another section / row were selected.
Has someone an idea why this does not work under ios7?
Your approach to find the "enclosing" table view cell of a text field is fragile,
because is assumes a fixed view hierarchy (which seems to have changed between
iOS 6 and iOS 7).
One possible solution would be to traverse up in the view hierarchy until the table view cell is found:
UIView *view = textField;
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = [view superview];
}
EditingCell *cell = (EditingCell *)view;
A completely different, but often used method is to "tag" the text field with the row
number:
cell.textField.tag = indexPath.row; // in cellForRowAtIndexPath
and then just use that tag in the text field delegate methods.
I was finding cells the same way you were. Now I use this quick method if I have a button in a cell and know the tableview I'm in. It'll return the tableviewcell.
-(UITableViewCell*)GetCellFromTableView:(UITableView*)tableView Sender:(id)sender {
CGPoint pos = [sender convertPoint:CGPointZero toView:tableView];
NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:pos];
return [tableView cellForRowAtIndexPath:indexPath];
}
Experiencing this problem in iOS 11, but not in 9 or 10, I overrode the func indexPath(for cell: UITableViewCell) -> IndexPath? method using the technique that #drexel-sharp detailed previously:
override func indexPath(for cell: UITableViewCell) -> IndexPath? {
var indexPath = super.indexPath(for: cell)
if indexPath == nil { // TODO: iOS 11 Bug?
let point = cell.convert(CGPoint.zero, to: self)
indexPath = indexPathForRow(at: point)
}
return indexPath
}

Looking for in all performing functions in all rows of a tableview, instead of visible cells

My question is clear,
I have a UITableView and UIMapView with annotations, when an annotation is tapped on the map, it will be found on the table and be selected since the user can recognize it.
But, if i try something it is only in visible cells, i am not able to do as i expected.
- (void)annotationTapped:(UITapGestureRecognizer *)recognizer{
if ( recognizer.state == UIGestureRecognizerStateEnded ) {
//NSLog(#"%#",[recognizer.view subviews]);
UIImageView *temp = (UIImageView*)[recognizer.view viewWithTag:1000];
UILabel *temp2 = (UILabel*)[temp viewWithTag:1001];
NSArray *tapAndFind;
if(isFiltered)
{
tapAndFind = filteredListContent;
}
else
{
tapAndFind = eczaneler;
}
for(int i=0;i<tapAndFind.count;i++)
{
Pharma *tempPharm = [tapAndFind objectAtIndex:i];
if([tempPharm.CustomerIndex isEqualToString:temp2.text])
{
EczaneCell *cell = (EczaneCell*)[tableView1 cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
for(EczaneCell * cell2 in [tableView1 visibleCells])
{
cell2.selected = NO;
}
cell.selected = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[tableView1 indexPathForCell:cell].row
inSection:[tableView1 indexPathForCell:cell].section];
[tableView1 scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
}
This is because your UITableView is just a presentation of your data, not a data itself. So, when you tap on annotation, you should somehow find a correspondence with a data, the position of your annotation data in collection. Then you may calculate/find out the index of row in table, and then you can perform UITableView's scrollToRowAtIndexPath:atScrollPosition. Alternatively, you can mark the cell to make it distinguishable.
In your code
EczaneCell *cell = (EczaneCell*)[tableView1 cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
can return nil for cell when the cell for given index path is invisible. That's why you should check against data, not table cells.

Animating all UICollectionViewCells in a UICollectionView

I was wondering what a good way to animate all the cells in a UICollectionView is. I'm trying to simulate editing in a UICollectionView. So what I want to do is shrink all the bounds of the UICollectionViewCells. So what I have is this:
- (IBAction)startEditingMode:(id)sender {
[_items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
[UIView animateWithDuration:0.25 animations:^{
cell.layer.transform = CATransform3DMakeScale(0.9, 0.9, 1);
}];
}];
}
It works, but I wasn't sure if there was a property on UICollectionView, or a better more standard way to do something like this. Thanks.
I would create a UICollectionViewLayout subclass. Add a BOOL property called editing. When editing changes, call invalidateLayout. Then in the attribute returned by the -layoutAttributesForItemAtIndexPath: method you can specify a transform.
The problem with your approach is that it affects only the visible cells. The UICollectionViewLayout subclass is nice because it will apply the transform to all of the cells even as new ones get added. And it moves all of the collection view layout handling out of the view controller.
Cell attributes can include frame, size, center, transform(3D), alpha, and your own custom attributes.
You'll change the value of editing in a -performBatchUpdates: block, as suggested by wL_.
- (IBAction)startEditingMode:(id)sender {
[self.collectionView performBatchUpdates:^{
((MyCollectionViewLayout *)self.collectionView.collectionViewLayout).editing = YES;
}
completion:NULL];
}
And in the UICollectionViewLayout subclass:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
if (self.editing) {
attributes.transform = CGAffineTransformMakeScale(0.9, 0.9);
}
else {
attributes.transform = CGAffineTransformIdentity;
}
return attributes;
}
Also note you (probably) don't need a 3D transform here. An affine transform is sufficient.
Have you tried using UICollectionView performBatchUpdates:?
Something like:
[collectionView performBatchUpdates:^{
[_items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
cell.layer.transform = CATransform3DMakeScale(0.9, 0.9, 1);
}];
} completion:^{}];

Resources