0

我设置了pagingEnabled = YES, 以便UITableView可以一次滚动一个页面距离。

tableView.pagingEnabled = YES;

但是页面大小并不总是等于UITableViewCell大小。的单元格宽度UITableView并不总是相同的。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {

      int index = indexPath.row;

      if(index == 0){
         return 20;
      }else if(index == g_lenth-1){
         return 20;
      }else{
         reutrn 100;
      }
  }

所以它并不总是在 a 的边缘滚动UITableViewCell

我该如何实现呢?

4

1 回答 1

1
- (void)scrollViewWillEndDragging:(UITableView *)tableView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    CGPoint offset = tableView.contentOffset;

    // 临界值处理
    BOOL hasScrollToTop = offset.y <= -tableView.contentInset.top;
    BOOL hasScrollToBottom = offset.y >= tableView.contentSize.height - tableView.bounds.size.height + tableView.contentInset.bottom;

    if (hasScrollToTop || hasScrollToBottom) return;

    //    NSLog(@"offset:%@ velocity:%@", NSStringFromCGPoint(offset), NSStringFromCGPoint(velocity));

    CGFloat velocityY = velocity.y;
    CGFloat panGestureVelocityY = [tableView.panGestureRecognizer velocityInView:self.view].y;

    NSLog(@"velocityY2:%.2f", panGestureVelocityY);
    if (velocityY > 0) {
        NSLog(@"松手时上滑,速度:%.2f", velocityY);
    } else if (velocityY < 0) {
        NSLog(@"松手时下滑,速度:%.2f", velocityY);
    } else {
        NSLog(@"松手时手静止");
    }

    NSArray<TableViewCell *> *visibleCells = tableView.visibleCells;

    NSUInteger firstMin = NSUIntegerMax;
    NSUInteger secondMin = NSUIntegerMax;
    for (TableViewCell *cell in visibleCells) {
        NSUInteger value = cell.model.index;
        if (value < firstMin) {  // 小于最小的元素 更新 1 和 2
            secondMin = firstMin;
            firstMin = value;
        } else if (value < secondMin && value != firstMin) {  // 小于倒数二的 更新 2
            secondMin = value;
        }
    }
    TableViewCell *topCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:firstMin inSection:0]];
    TableViewCell *secondCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:secondMin inSection:0]];

    NSIndexPath *topCellIndexPath = [self.tableView indexPathForCell:topCell];
    NSIndexPath *secondCellIndexPath = [self.tableView indexPathForCell:secondCell];
    if (topCellIndexPath) {
        if (!secondCellIndexPath) secondCellIndexPath = topCellIndexPath;

        CGRect topCellRect = [tableView rectForRowAtIndexPath:topCellIndexPath];
        CGRect secondCellRect = [tableView rectForRowAtIndexPath:secondCellIndexPath];

        CGRect topCellRectToTableView = [topCell convertRect:topCell.bounds toView:self.tableViewMirrorView];
        CGFloat topCellHalfHeight = CGRectGetHeight(topCellRectToTableView) * 0.5;

        CGFloat thresholdValue = 50;
        if (thresholdValue > topCellHalfHeight) {
            thresholdValue = topCellHalfHeight;
        }

        NSLog(@"topCell rect:%@", NSStringFromCGRect(topCellRect));
        NSLog(@"topCellRectToTableView rect:%@ ", NSStringFromCGRect(topCellRectToTableView));

        // 最上面的 cell 顶部是否可见
        BOOL isTopCellYVisable = topCellRectToTableView.origin.y > 0;
        if (velocityY == 0) {
            if (isTopCellYVisable) {
                // 最上面的 cell 此 rect 大于 0 说明 是 headerView 在显示,或者内边距之内
                targetContentOffset->y = topCellRect.origin.y;
            } else {
                // 是否划过了阈值
                BOOL isPastThresholdValue = fabs(topCellRectToTableView.origin.y) > thresholdValue;
                if (panGestureVelocityY > 0) {
                    // 停止之前是下滑
                    isPastThresholdValue = (topCellRectToTableView.size.height - fabs(topCellRectToTableView.origin.y)) > thresholdValue;
                    if (isPastThresholdValue) {
                        targetContentOffset->y = topCellRect.origin.y;
                    } else {
                        targetContentOffset->y = secondCellRect.origin.y;
                    }
                } else if (panGestureVelocityY < 0) {
                    // 停止之前是上滑
                    isPastThresholdValue = fabs(topCellRectToTableView.origin.y) > thresholdValue;

                    if (isPastThresholdValue) {
                        targetContentOffset->y = secondCellRect.origin.y;
                    } else {
                        targetContentOffset->y = topCellRect.origin.y;
                    }
                } else {
                    if (isPastThresholdValue) {
                        targetContentOffset->y = secondCellRect.origin.y;
                    } else {
                        targetContentOffset->y = topCellRect.origin.y;
                    }
                }
            }
        } else if (velocityY > 1) {  // 上滑很快,直接下一个
            if (isTopCellYVisable) {
                // 最上面的 cell 此 rect 大于 0 说明 是 headerView 在显示,或者内边距之内
                targetContentOffset->y = topCellRect.origin.y;
            } else {
                targetContentOffset->y = secondCellRect.origin.y;
            }
        } else if (velocityY > 0) {
            if (isTopCellYVisable) {
                // 最上面的 cell 此 rect 大于 0 说明 是 headerView 在显示,或者内边距之内
                targetContentOffset->y = topCellRect.origin.y;
            } else {
                // 是否划过了阈值
                BOOL isPastThresholdValue = fabs(topCellRectToTableView.origin.y) > thresholdValue;
                if (isPastThresholdValue) {
                    targetContentOffset->y = secondCellRect.origin.y;
                } else {
                    targetContentOffset->y = topCellRect.origin.y;
                }
            }
        } else if (velocityY < -0.8) {  // 下滑很快,直接上一个
            if (isTopCellYVisable) {
                targetContentOffset->y = 0;
            } else {
                targetContentOffset->y = topCellRect.origin.y;
            }
        } else {  // 其它速度下滑
            if (isTopCellYVisable) {
                targetContentOffset->y = 0;
            } else {
                // 是否划过了阈值
                BOOL isPastThresholdValue = (topCellRectToTableView.size.height - fabs(topCellRectToTableView.origin.y)) > thresholdValue;
                if (isPastThresholdValue) {
                    targetContentOffset->y = secondCellRect.origin.y;
                } else {
                    targetContentOffset->y = topCellRect.origin.y;
                }
            }
        }
    }
}

#pragma mark - lazy load
- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];

        _tableView.backgroundColor = UIColor.whiteColor;
        // 以下三项是适配iOS 11刷新时会漂移的情况
        _tableView.estimatedSectionHeaderHeight = 0;
        _tableView.estimatedSectionFooterHeight = 0;
        _tableView.estimatedRowHeight = 0;
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _tableView.showsVerticalScrollIndicator = NO;
        _tableView.showsHorizontalScrollIndicator = NO;
        _tableView.sectionFooterHeight = 0;
        _tableView.sectionHeaderHeight = 0;
        _tableView.alwaysBounceVertical = true;
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 150)];
        headerView.backgroundColor = [UIColor redColor];
        _tableView.tableHeaderView = headerView;
        _tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, CGFLOAT_MIN)];

        _tableView.decelerationRate = UIScrollViewDecelerationRateFast;

        if (@available(iOS 11.0, *)) {
            _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
        if (@available(iOS 13.0, *)) {
            _tableView.automaticallyAdjustsScrollIndicatorInsets = false;
        }
    }
    return _tableView;
}

- (UIView *)tableViewMirrorView {
    if (_tableViewMirrorView) return _tableViewMirrorView;
    UIView *view = [[UIView alloc] init];
    view.frame = self.tableView.frame;
    view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
    _tableViewMirrorView = view;
    return _tableViewMirrorView;
}
于 2021-08-13T17:33:05.233 回答