Force UITableView to Scroll to Tops of Cells

后端 未结 6 2023
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-29 13:41

Is there a way to make UITableViews scroll cell to cell? That is, the top of the Table View is always the top of a UITableViewCell.

I tried the pageation flag, but t

相关标签:
6条回答
  • 2020-12-29 13:48

    Although totally correct, I didn't find the answer by @randle very helpful. I read the developers documentation, and I was even more confused. How ever I finally discovered how simple the answer was, but sometimes we need a little but more help than "call this method". See under the comment // scroll to row! here:

    - (BOOL)textFieldShouldReturn:(UITextField *)textField 
    {
        if (textField == self.firstInput) {
            [self.secondInput becomeFirstResponder];
    
            // scroll to row!
            [self.tableView scrollToRowAtIndexPath: // use the method
                 [NSIndexPath indexPathForRow:1     // get 2nd row (nth row...)
                                    inSection:0]    // in 1st section (...)
                             // set position: you can use bottom, middle or top.
                             atScrollPosition:UITableViewScrollPositionBottom  
                                     animated:YES]; // YES or NO.
    
        } else if (textField == self.secondInput) {
            [textField resignFirstResponder];
        }
        return YES;
    }
    

    Now, this is for a static cell tableView. I know the amount of rows, I know which row I am going to. This could be expanded out to better code, and accessing variables programmatically, but it show HOW this code works in practice at a low level.

    I hope this adds a layer of usefulness to anyone else searching the forum.

    I did a complete write up of the method here: http://iosanswers.blogspot.com/2012/02/table-view-forms-scroll-to-selected.html

    0 讨论(0)
  • 2020-12-29 13:51

    If you have sections, I found this the most reliable approach:

    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate(BOOL)decelerate {
        if (decelerate == NO) {
            [self autoAdjustScrollToTop];
        }
    }
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        [self autoAdjustScrollToTop];
    } 
    - (void)autoAdjustScrollToTop {
        // compare the top two visible rows to the current content offset
        // and auto scroll so that the best row is snapped to top
        NSArray *visibleRows = [self.tableView indexPathsForVisibleRows];
        NSIndexPath *firstPath = visibleRows[0];
        NSIndexPath *secondPath = visibleRows[1];
        CGRect firstRowRect = [self.tableView rectForRowAtIndexPath:firstPath];
        [self.tableView scrollToRowAtIndexPath:(firstRowRect.origin.y > self.tableView.contentOffset.y ? firstPath : secondPath) atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }
    
    0 讨论(0)
  • 2020-12-29 13:59

    You simply need to call scrollToRowAtIndexPath:atScrollPosition:animated: and pass it the right index path for the cell you want.

    0 讨论(0)
  • 2020-12-29 14:02

    This approach handles a table view with varying row heights. It assumes the table view has a single section.

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                         withVelocity:(CGPoint)velocity
                  targetContentOffset:(inout CGPoint *)targetContentOffset {
    
        // Find the row where the animation will currently end.
        NSInteger targetRow = [[self.tableView indexPathForRowAtPoint:*targetContentOffset] row];
    
        // Tell the animation to end at the top of that row.
        *targetContentOffset = [self offsetForTopOfRow:targetRow];
    }
    

    The offset is calculated by this helper method, which sums the heights of all rows above the target row.

    - (CGPoint)offsetForTopOfRow:(NSInteger)row {
    
        CGPoint offset = CGPointZero;
    
        for (int i = 0; i < row; i++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
            CGFloat height = [self.tableView.delegate tableView:self.tableView heightForRowAtIndexPath:indexPath];
            offset.y += height;
        }
    
        return offset;
    }
    
    0 讨论(0)
  • 2020-12-29 14:05

    UTTableView is a subclass of UIScrollView, so you can use scrollViewDidScroll method to rearrange your TableView scroll position after scroll.

    You can use tableView.contentOffset to get where is your current scroll position. And by dividing it to a meaningful number you can get which cell is on top.

    int cellIndex = tableView.contentOffset / cellHegiht;
    

    Or you can get currently visible cell on center (top, bottom) like this:

    NSArray *indexPathsForVisibleRows = [tableView indexPathsForVisibleRows];
    NSIndexPath *selectedIndexPath = [indexPathsForVisibleRows objectAtIndex:(indexPathsForVisibleRows.count / 2)]; //this gets center cell
    

    After calculating which cell should be clicked by its edge on top (or bottom) you can correct the drift from cell edge by calling:

    [tableView scrollToRowAtIndexPath:selectedIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
    

    You can use UIScrollViewDelegate methods to activate snapping. You can activate either when the scrolling animation completed or while the animation still continues. This will generate different user interaction and can't say one is better then another.

    But just implementing following method and nothing else looks like going to be my favorite:

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                         withVelocity:(CGPoint)velocity
                  targetContentOffset:(inout CGPoint *)targetContentOffset {
        int cellHeight = 41;
        *targetContentOffset = CGPointMake(targetContentOffset->x,
                                           targetContentOffset->y - (((int)targetContentOffset->y) % cellHeight));
    }
    

    This method gets called when user touches up on TableView to notify application. targetContentOffset is an inout variable so you can actually set final scroll position while animation is continuing. Using right cellHeight, your TableView will always snap to cells.

    0 讨论(0)
  • 2020-12-29 14:05

    This works well if you have sections and rows with static heights.

    func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        // Adjust target offset so that cells are snapped to top
        let cellHeight: CGFloat = 44
        let headerHeight: CGFloat = 30
        let section = (indexPathsForVisibleRows?.first?.section ?? 0) + 1
        targetContentOffset.memory.y -= (targetContentOffset.memory.y % cellHeight) - (CGFloat(sectionIndex) * headerHeight)
    }
    
    0 讨论(0)
提交回复
热议问题