Ios 将UITableView滑动到屏幕上,是否继续滑动?

Ios 将UITableView滑动到屏幕上,是否继续滑动?,ios,objective-c,uitableview,uiscrollview,Ios,Objective C,Uitableview,Uiscrollview,我想要一个从屏幕外开始,可以在屏幕上滚动,到达顶部,并保持滚动的tableview。我已经在下面展示了所需的交互 我试过两种方法,两种方法都不能完全满足我的需要 我做的第一件事是将tableview放在scrollview中,并在tableview上检测到平移时移动scrollview。这会阻止tableview中的触摸,即使我能检测到tableview何时到达屏幕顶部,我也不确定如何继续滚动 我尝试的第二件事是将scrollview的内容大小设置为tableview的高度。这可以让tablev

我想要一个从屏幕外开始,可以在屏幕上滚动,到达顶部,并保持滚动的tableview。我已经在下面展示了所需的交互

我试过两种方法,两种方法都不能完全满足我的需要

我做的第一件事是将tableview放在scrollview中,并在tableview上检测到平移时移动scrollview。这会阻止tableview中的触摸,即使我能检测到tableview何时到达屏幕顶部,我也不确定如何继续滚动

我尝试的第二件事是将scrollview的内容大小设置为tableview的高度。这可以让tableview滚动,但我似乎只能在标记为“列表项1”的初始小矩形中接收触摸。当tableview滚动时,我无法抓住中间部分再滚动

建立这种互动的最佳方式是什么编辑:地图将此底部视图包围在左侧、右侧和大部分顶部。向上拉底视图时,地图左右可见

1.

2.

3。)(这将保持滚动,滚动的项目数量与列表中的项目数量相同。)

为什么不彻底改变这一点呢。你说你有一张地图“在”桌面视图下面。因此,当向上滚动时,地图将被表视图隐藏。我想当你再次向下滚动时,地图会显示出来吗

您应该能够通过使用
UITableView
标题来实现这一点。节标题或表视图标题。它们在滚动时的行为略有不同

我可能会这样做

在表格上使用
表格视图标题
。在此标题中放置地图视图

默认情况下,这将固定在表格顶部,因此如果向上滚动表格,则地图将随之从屏幕顶部滑出

但是,如果您随后拦截scroll view委托方法
-(void)scrollViewDidScroll:(UIScrollView*)scrollView然后您可以计算出表格是否向上滚动,并偏移地图视图,使其保持在原来的位置

i、 e.如果表格滚动到(0,10),则将地图偏移到(0,-10),使其看起来没有移动


这将为您提供tableview的滚入和滚出功能,并保持地图在视图中并对触摸做出响应。

您应该能够通过将表格视图的顶部
内容插入设置为较高的值(如sha在评论中所建议的)来轻松完成此操作然后将UITableView设置为子类,以便可以重写
-pointInside:withEvent:
。使用该值和当前的
contentOffset
,您可以确定传入事件是否在您想要滚动的区域内,并相应地返回YES或NO;如果您返回“否”,则触摸应按预期进入地图视图。

我猜您希望看到以下内容:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.rowHeight = 44;
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight };
    self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top);
}

或者这个:

我把我的桌子视图放在我的地图视图上。我将表视图的
contentInset
contentOffset
设置如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.rowHeight = 44;
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight };
    self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top);
}
请注意,尽管默认行高为44,
tableView.rowHeight
返回-1,除非您显式设置它。(在情节提要中将其设置为44不会改变此设置。)

我使用了
UITableView
的子类,其中我做了两件事:

  • 我显式地设置了self.backgroundColor=[UIColor clearColor]
  • 。我发现在情节提要中将背景色设置为“清除”不起作用

  • 我超越了
    点内部:with事件:

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
        return point.y >= 0 && [super pointInside:point withEvent:event];
    }
    
  • 请注意,您并不关心此处的
    contentInset
    。表视图的
    contentOffset.y
    (与其
    bounds.origin.y
    相同)在其顶部内容插入显示时设置为负数。当项目0的顶部位于表视图的上边缘时,它被设置为0,而当项目位于屏幕的下边缘时,情况并非如此

    您可能需要的另一件事是防止表在屏幕上停止一半。如果用户将项目0拖到屏幕的一半,则希望表格滚动,以便项目0始终位于屏幕顶部(如果有足够的项目),如果用户将项目0拖到屏幕的一半,则希望表格滚动,以便只显示项目0

    为此,我让视图控制器充当表视图的委托,并实现此委托方法,该方法继承自
    UIScrollViewDelegate

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
        CGFloat yMin = -self.tableView.contentInset.top;
        CGFloat yMax = MIN(0, self.tableView.contentSize.height - self.tableView.bounds.size.height);
        if (targetContentOffset->y < yMax) {
            if (velocity.y < 0) {
                targetContentOffset->y = yMin;
            } else {
                targetContentOffset->y = yMax;
            }
        }
    }
    
    但这实际上不起作用,因为(在我的实现中)滚动视图只有一个大的子视图,
    ScrollContentView
    。因此,我们需要在
    ScrollContentView
    中执行相同的操作:

    @implementation ScrollContentView
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        UIView *hitView = [super hitTest:point withEvent:event];
        return hitView == self ? nil : hitView;
    }
    
    如果触地点落在表外,则足以将触地点传递到地图视图

    我还使用
    ScrollContentView
    布局表格并设置滚动视图的内容大小:

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        // Layout of subviews horizontally:
        // [gutter/2][gutter][subview][gutter][subview][gutter][subview][gutter][gutter/2]
        // where 3 * gutter + subview = width of superview
    
        CGSize superSize = self.superview.bounds.size;
        CGFloat x = kGutterWidth * 3 / 2;
        CGFloat subWidth = superSize.width - kGutterWidth * 3;
    
        for (UITableView *subview in self.subviews) {
            subview.frame = CGRectMake(x, 0, subWidth, superSize.height);
            x += subWidth + kGutterWidth;
    
            CGFloat topInset = superSize.height - subview.rowHeight;
            subview.contentInset = (UIEdgeInsets){ .top = topInset };
            subview.contentOffset = CGPointMake(0, -topInset);
        }
    
        x += kGutterWidth / 2;
        self.frame = CGRectMake(0, 0, x, superSize.height);
        ((UIScrollView *)self.superview).contentSize = self.bounds.size;
    
        _pageWidth = subWidth + kGutterWidth;
    }
    
    我还将视图控制器设置为滚动视图的委托,并实现了委托方法,以强制滚动视图在“页面”(表格)边界上停止:

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
        CGFloat pageWidth = contentView.pageWidth;
    
        // Force scroll view to stop on a page boundary.
        CGFloat pageNumber = targetContentOffset->x / pageWidth;
        if (velocity.x < 0) {
            pageNumber = floor(pageNumber);
        } else {
            pageNumber = ceil(pageNumber);
        }
        pageNumber = MAX(0, MIN(pageNumber, contentView.subviews.count - 1));
        targetContentOffset->x = pageNumber * pageWidth;
    }
    
    -(void)ScrollViewWillendDraging:(UIScrollView*)带速度的scrollView:(CGPoint)速度targetContentOffset:(inout CGPoint*)targetContentOffset{
    CGFloat pageWidth=contentView.pageWidth;
    //强制滚动视图在页面边界上停止。
    CGFloat pageNumber=targetContentOffset->x/pageWidth;
    if(速度x<0){
    页码=楼层(页码);
    }否则{
    页码=ceil(页码);
    }
    pageNumber=MAX(0,MIN(pageNumber,contentView.subviews.count-1));
    targetContentOffset->x=pageNumber*pageWidth;
    }
    
    结果是:


    我已使用此版本更新了。

    为什么不将contentInset更改为顶部的大屏幕?这样,即使您的tableView将占据整个屏幕,列表项也只会在最开始的时候启动