Reputation: 1360
I would like to fire an event when the subview of a UITableviewCell reaches a certain point on the screen, say for example when its origin.y reaches 44 points. It would also be nice to know if it was being scrolled up or down when it reached that point. I was playing with KVO on the frame of the subview but this seems fixed to the cell so no changes with that. Is this task possible?
Upvotes: 0
Views: 435
Reputation: 2037
Vertical position of UITableViewCell is defined by its frame
property, which represents position and size of that cell within its superview, UITableView. Typically, the frame
property of the cell is changing only once for every time that UITableView requests a cell from its delegate for specific index path. That's it, UITableView gets a cell, places it in itself and that cell just lays there unchanged until rectangle stored in bounds
property of UITableView ceases to include rectangle stored in the frame
property of that cell. In that case UITableView marks that cell as hidden and places it into the pool of reusable cells.
Since the process of scrolling in essence is not a repositioning of subviews – it is merely a curious illusion of shifting a bounds
viewport of UITableView – constant observing of UITableViewCell's properties are pointless.
Moreover, the frame
property of subview of UITableViewCell also represents a position and size of that subview within its container, UITableViewCell. It is also will not change on scroll.
You need to observe changes in UITableView bounds
property, which is also represented by contentOffset
by the way. UITableView happens to be a subclass of UIScrollView, so you can use its delegate methods, such as -scrollViewDidScroll:
, like in this simple example:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UITableView *tableView = (UITableView *)scrollView;
// current position
CGFloat currentY = tableView.bounds.origin.y;
// current inset
CGFloat currentInset = tableView.contentInset.top;
// trigger line position
CGFloat triggerY = currentInset + currentY + kYourTriggerPosition;
// nice visual mark
UIView *line = [tableView viewWithTag:88];
if (!line) {
line = [[UIView alloc] initWithFrame:CGRectZero];
line.tag = 88;
line.backgroundColor = [UIColor redColor];
[tableView addSubview:line];
}
line.frame = CGRectMake(0, triggerY, tableView.bounds.size.width, 1);
// determine scroll direction
BOOL scrollingUp = currentY > self.previousY;
// all visible cells
NSArray *visibleCells = tableView.visibleCells;
[visibleCells enumerateObjectsUsingBlock:^(UITableViewCell *cell, NSUInteger idx, BOOL *stop) {
// subview
UIView *subview = [cell viewWithTag:kYourSubviewTag];
// subview frame rect in UITableView bounds
CGRect subviewRect = [subview convertRect:subview.frame toView:tableView];
// trigger line within subview?
BOOL triggered = (CGRectGetMinY(subviewRect) <= triggerY) && (CGRectGetMaxY(subviewRect) >= triggerY);
if (triggered) {
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
NSLog(@"moving %@, triggered for cell at [%2d:%2d]", @[@"down", @"up"][scrollingUp], indexPath.section, indexPath.row);
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
// save current position for future use
self.previousY = currentY;
}
Upvotes: 2
Reputation: 676
Here's a simple approach, which you can use if you have only one section without section header.
Add this to your implementation:
CGFloat lastContentOffSet;
And then add this delegate method of scrollview as tableview is also a scrollview.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat cellHeight = 50;
CGFloat touchingPoint = 44.0f;
NSInteger rowNo = floor(scrollView.contentOffset.y / cellHeight);
NSInteger startPoint = (rowNo * cellHeight);
if (scrollView.contentOffset.y > lastContentOffSet) {
NSLog(@"Row %ld scrolled down", (long)rowNo);
if (scrollView.contentOffset.y > startPoint + touchingPoint) {
// Do something here
NSLog(@"Do something here");
}
}
else {
NSLog(@"Row %ld scrolled up", (long)rowNo);
if (scrollView.contentOffset.y > startPoint + touchingPoint) {
// Do something here
NSLog(@"Do something here");
}
}
lastContentOffSet = scrollView.contentOffset.y;
}
Change value of the cellheight according to your tableview cell and the distance of that subview with the cell.
Let me know if this code helped. :)
Upvotes: 1
Reputation: 381
Since I can not comment I am writing as an Answer
Changing the answer for the requirement.
Here is how I think it can be done, you need to have your custom UITableViewCell
which has a function which can take in co-ordinates (again based on your logic if you just want an intersection where a cell just touches a boundary or if it has to be at a precise position in a frame), so your function would take the co-ordinates and will return a true and a false if it will tell you if the condition is met, and in your cellForTable
function you call the function of UITableView cell to check if your condition is met, if it is in your view you create a subview at the exact location. You can also modify the function to return you the exact frame-cordinates so you can use them to create a subview\
Upvotes: 1
Reputation: 3017
Reach that subview
of UITableViewCell
with cellForRowAtIndexPath
or tableView.visibleCells
, then call convertRectToView:
on that subview
.
convertRectToView:
allows you to do translations on different coordinate systems. For example, you can detect where that subview
appears on screen by translating its frame
within its superview
into viewController.view
For more: Apple Documentation
Upvotes: 1