2012-03-17 43 views
0

我有一个具有表格视图的VC。当发生事件时,我想从主视图的顶部放入一个UIView。当用户滚动表格视图时,我想重新布局视图,以便视图中的“滚动”。我想我会通过移动upperView的框架并调整表格视图的大小(都与滚动偏移量有关)。我得到它几乎工作如下:滚动调整UITableView的尺寸

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 

    CGFloat contentOffsetY = scrollView.contentOffset.y; 

    if (contentOffsetY > 0) { 
     CGFloat upperHeight = self.upperView.frame.size.height; 
     CGFloat fullTableHeight = self.view.frame.size.height; 

     CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight; 

     self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight); 
     scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY)); 
    } 
    NSLog(@"%f", self.upperView.frame.origin.y); 
} 

上视图的起源从0,0开始。

问题是,在来回拖动一点点之后,我失去了该视图顶部的几个像素。它似乎无法让它的原点y回到零。日志记录读取负值,只有最小的拖动才能达到-1。有没有人做过这样的事情?如果你能提供帮助,我们非常感激。

回答

1

听起来就像您总是在显示插入视图时将表视图滚动到顶部。假设情况如此,有一个更好的方法来做到这一点。

UITableView继承UIScrollViewcontentInset财产。 contentInset属性在滚动视图的每个边上定义边框。每个边框都有自己的厚度,默认为零。这些边界只影响滚动视图允许用户滚动内容的距离 - 它们不会隐藏内容!如果您设置的顶部插入大于零,并为滚动视图指定一个负Y原点的子视图,则该子视图可以在边框中可见,并将随滚动视图内容的其余部分一起滚动。

因此,我们将表视图的顶部边界设置为下拉式的视线的高度,并添加下拉鉴于与它的起源设定其高度的负表视图的一个子视图。这将使它完全适合表格视图第一行上方的屏幕,并且它将与表格视图一起滚动。当我们检测到drop-in视图已经完全在屏幕外滚动时,我们可以从表视图中将其删除,并将表视图的顶部插入设置回零。

我们需要跟踪落鉴于当前状态的实例变量:

typedef enum { 
    DropInViewStateHidden, 
    DropInViewStateAppearing, 
    DropInViewStateVisible 
} DropInViewState; 

@implementation ViewController { 
    DropInViewState _dropInViewState; 
} 

在我的测试项目,我只是用一个按钮来触发下拉式的视图。这里的动作:

- (IBAction)dropIn { 
    if (_dropInViewState != DropInViewStateHidden) 
     return; 

    CGRect frame = self.dropInView.frame; 
    frame.origin.y = -frame.size.height; 
    self.dropInView.frame = frame; 
    [self.tableView addSubview:self.dropInView]; 

    self.tableView.contentInset = UIEdgeInsetsMake(frame.size.height, 0, 0, 0); 
    [self.tableView setContentOffset:frame.origin animated:YES]; 

    _dropInViewState = DropInViewStateAppearing; 
} 

当表视图滚动时,我们检查插入视图的状态。如果它处于“可见”状态并且已经在屏幕外滚动,我们将其隐藏。有一点棘手,因为当我们使插入视图可见并将其滚动到屏幕上时,我们可以收到scrollViewDidScroll:消息,这会让我们认为插入视图已隐藏。这就是为什么我们从DropInViewStateAppearing状态开始,当我们知道视图已经出现时,转换到DropInViewVisible状态。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 
    switch (_dropInViewState) { 
     case DropInViewStateHidden: 
      break; 
     case DropInViewStateVisible: 
      if (scrollView.contentOffset.y >= 0) { 
       // dropInView has been scrolled off-screen 
       self.tableView.contentInset = UIEdgeInsetsZero; 
       [self.dropInView removeFromSuperview]; 
       _dropInViewState = DropInViewStateHidden; 
       break; 
      } 
     case DropInViewStateAppearing: 
      // When I first add dropInView to tableView and tell tableView 
      // to scroll to reveal dropInView, I may get a bunch of 
      // scrollViewDidScroll: messages with contentOffset.y >= 0. 
      // I don't want those messages to hide dropInView, so I sit in 
      // DropInViewStateAppearing until contentOffset.y goes negative, 
      // which means at least part of dropInView is actually on-screen. 
      if (scrollView.contentOffset.y < 0) 
       _dropInViewState = DropInViewStateVisible; 
      break; 
    } 
} 
+0

我有一个搜索栏和拉到刷新的东西也争夺顶部嵌入区,所以我仍然在绘图板,但感谢您的好,彻底的答案。 – danh 2012-03-17 14:49:47

0

想通了:在反弹期间,UITableView没有彻底地发送didScroll消息。这就是为什么我错过了几个像素。在反弹期间调整大小会使反弹混乱并停止。在我上面的代码上的修复允许反弹工作(通过移动,而不是调整表的大小),并确保在反弹期间正确放置上部视图(当contentOffset.y < = 0时)。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 

    CGFloat contentOffsetY = scrollView.contentOffset.y; 

    CGFloat upperHeight = self.upperView.frame.size.height; 
    CGFloat fullTableHeight = self.view.frame.size.height; 

    CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight; 

    if (contentOffsetY > 0) { 
     self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight); 
     scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY)); 
    } else { 
     self.upperView.frame = CGRectMake(0, 0, 320, upperHeight); 
     scrollView.frame = CGRectMake(0.0, upperHeight, 320, scrollView.frame.size.height); 
    } 
    [super scrollViewDidScroll:scrollView]; 
}