【问题标题】:Add snap-to position in a UITableView or UIScrollView在 UITableView 或 UIScrollView 中添加对齐位置
【发布时间】:2014-01-23 07:42:27
【问题描述】:

是否可以在 UITableView 或 UIScrollView 中添加对齐位置?我的意思不是如果我按下按钮或调用某种方法来执行此操作,则不会自动滚动到某个位置,我的意思是如果我围绕特定点滚动滚动视图或表格视图,例如0, 30,它将自动捕捉到它并留在那里?因此,如果我的滚动视图或表格视图滚动,然后用户在0, 250, 35 之间移动,它会自动“捕捉”并滚动到那里吗?我可以想象可能会在 UIScrollView 的 scrollViewDidEndDragging:WillDecelerate:scrollViewWillBeginDecelerating: 方法中放入一个 if 语句来测试该位置是否落在该区域,但我不确定如何在 UITableView 的情况下实现这一点。任何指导将不胜感激。

【问题讨论】:

  • 你实际上是在正确的行兄弟。你能粘贴一些你尝试过的代码吗?
  • @Pavan 请看我的回答。
  • 我看过你的帖子Milo,我也回复了你的帖子。如果我为您发布一个有关如何正确执行此操作的 xcode 项目,这样您就可以拥有一个动态滚动视图,而您不需要不断更改您的滚动视图委托方法,这会有用吗?这将是一个更清洁的解决方案,伙计:) 让我知道
  • 如果您为滚动视图打开paging,它将自动执行此操作。

标签: ios objective-c uitableview uiscrollview


【解决方案1】:

此代码可让您捕捉到一个单元格,即使单元格具有可变(或未知)高度,并且如果您滚动到该行的下半部分,它将捕捉到下一行,使其更“自然” .

原始 Swift 4.2 代码:(为方便起见,这是我开发和测试的实际代码)

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    guard var scrollingToIP = table.indexPathForRow(at: CGPoint(x: 0, y: targetContentOffset.pointee.y)) else {
        return
    }
    var scrollingToRect = table.rectForRow(at: scrollingToIP)
    let roundingRow = Int(((targetContentOffset.pointee.y - scrollingToRect.origin.y) / scrollingToRect.size.height).rounded())
    scrollingToIP.row += roundingRow
    scrollingToRect = table.rectForRow(at: scrollingToIP)
    targetContentOffset.pointee.y = scrollingToRect.origin.y
}

(翻译)Objective-C 代码:(因为这个问题被标记为objective-c

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    NSIndexPath *scrollingToIP = [self.tableView indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];
    if (scrollingToIP == nil)
        return;
    CGRect scrollingToRect = [table rectForRowAtIndexPath:scrollingToIP];
    NSInteger roundingRow = (NSInteger)(round(targetContentOffset->y - scrollingToRect.origin.y) / scrollingToRect.size.height));
    scrollingToIP.row += roundingRow;
    scrollingToRect = [table rectForRowAtIndexPath:scrollingToIP];
    targetContentOffset->y = scrollingToRect.origin.y;
}

【讨论】:

  • 完美!作为一个插件工作,变化很小。欣赏它。
【解决方案2】:

如果您真的必须手动执行此操作,这里有一个 Swift3 版本。但是,强烈建议您只为 UITableView 打开分页,这已经为您处理好了。

let cellHeight = 139
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    targetContentOffset.pointee.y = round(targetContentOffset.pointee.y / cellHeight) * cellHeight
}

// Or simply
self.tableView.isPagingEnabled = true

【讨论】:

    【解决方案3】:

    在 Swift 2.0 中,当表格有内容插入和简化事物时,ninefifteen's great answer 变为:

    func scrollViewWillEndDragging(scrollView:            UIScrollView,
                                   withVelocity velocity: CGPoint,
                                   targetContentOffset:   UnsafeMutablePointer<CGPoint>)
    {
        let cellHeight = 44
        let y          = targetContentOffset.memory.y + scrollView.contentInset.top + cellHeight / 2
        var cellIndex  = floor(y / cellHeight)
    
        targetContentOffset.memory.y = cellIndex * cellHeight - scrollView.contentInset.top;
    }
    

    只需添加cellHeight / 2,ninefifteen 的if-statement 就不再需要增加索引了。

    【讨论】:

      【解决方案4】:

      这是 Swift 2.0 的等价物

      func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
          let cellWidth = CGRectGetWidth(frame) / 7   // 7 days
          var index = round(targetContentOffset.memory.x / cellWidth)
          targetContentOffset.memory.x = index * cellWidth
      }
      

      只要你使用round而不是floor,这种复杂的四舍五入就完全没有必要了

      【讨论】:

        【解决方案5】:

        就像 Pavan 所说,scrollViewWillEndDragging: withVelocity: targetContentOffset: 是您应该使用的方法。它适用于表格视图和滚动视图。如果您使用的是表格视图或垂直滚动​​的滚动视图,下面的代码应该适合您。 44.0 是示例代码中表格单元格的高度,因此您需要将该值调整为单元格的高度。如果用于水平滚动的滚动视图,请将 y 换成 x,并将 44.0 更改为滚动视图中各个部分的宽度。

        - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
        {
            // Determine which table cell the scrolling will stop on.
            CGFloat cellHeight = 44.0f;
            NSInteger cellIndex = floor(targetContentOffset->y / cellHeight);
        
            // Round to the next cell if the scrolling will stop over halfway to the next cell.
            if ((targetContentOffset->y - (floor(targetContentOffset->y / cellHeight) * cellHeight)) > cellHeight) {
                cellIndex++;
            }
        
            // Adjust stopping point to exact beginning of cell.
            targetContentOffset->y = cellIndex * cellHeight;
        }
        

        【讨论】:

        • 干杯兄弟,我确实尝试过告诉他几次。但我认为他坚持自己的方法。
        【解决方案6】:

        我相信如果你使用委托方法:

        - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
            NSLog(@"%f",scrollView.contentOffset.y);
            if (scrollView.contentOffset.y > 350 && scrollView.contentOffset.y < 370)
            {
                NSLog(@"setContentOffset");
                [scrollView setContentOffset:CGPointMake(0, 350) animated:YES];
            }
        }
        

        玩弄它直到你得到想要的行为。 也许计算下一个 tableViewCell/UIView 的下一个顶部边缘并在减速时停在最近的顶部。

        原因:if (scrollView.contentOffset.y &gt; 350 &amp;&amp; scrollView.contentOffset.y &lt; 370) 是滚动视图在快速跳转时调用scrollViewDidScroll,所以我在 if 之间给出了一个。

        您还可以通过以下方式知道速度正在变慢:

        - (void)scrollViewDidScroll:(UIScrollView *)scrollView
        {
            NSLog(@"%f",scrollView.contentOffset.y);
            int scrollSpeed = abs(scrollView.contentOffset.y - previousScrollViewYOffset);
            previousTableViewYOffset = scrollView.contentOffset.y;
            if (scrollView.contentOffset.y > 350 && scrollView.contentOffset.y < 370 && scrollSpeed < minSpeedToStop)
            {
                NSLog(@"setContentOffset");
                [scrollView setContentOffset:CGPointMake(0, 350) animated:YES];
            }
        }
        

        【讨论】:

          【解决方案7】:

          我强烈建议您使用 scrollViewWillEndDragging: withVelocity: targetContentOffset: 方法,而是用于完全用于您的目的。将目标内容偏移设置到您想要的位置。

          我还建议您查看已在 SO 上发布的重复问题。

          Take a look at these posts

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-02-26
            • 2023-03-16
            • 2016-12-18
            • 1970-01-01
            • 2014-05-21
            • 1970-01-01
            相关资源
            最近更新 更多