iOS:当用户向下拖动时,如何拉伸/调整UITableView表头?

29
使用Storyboard,我将一个imageView放置在tableViewheaderView中,并放置在ViewController中。

我的Storyboard设置如下:

enter image description here

根据用户查看的数据,viewController将显示或隐藏headerView。我的问题是,当headerView可见并且用户在tableView上向下拖动时,如何使imageView粘附到navigationBartableView上,并在调整大小以覆盖它们之间的空间时?

这是它目前的效果:

enter image description here

但这是我想要的效果:

enter image description here

任何帮助都将不胜感激。我已经查看了一些视差库,但没有一个支持sectionTitles,并且我也不一定需要视差效果。当用户向上滚动时,我希望它弹回到常规视图而不是隐藏headerView。谢谢!

更新:

我已经按照下面Dany的建议进行了操作:

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

CGRect initialFrame = CGRectMake(0, 0, 320, 160);

if (scrollView.contentOffset.y < 0) {

    initialFrame.size.height =! scrollView.contentOffset.y;
    childHeaderView.frame = initialFrame;
} }

childHeaderView是一个imageView,但是当我向下拖动时,图片会向上移动(像导航栏后面的一半),并且不会回到原来的位置。有什么建议吗?非常感谢!谢谢!


你找到解决方案了吗? - Nischal Hada
6个回答

7

1
这确实很棒,但对于@KingPolycon来说没有用处,因为他在表视图顶部使用了一张图片,在这种情况下处理起来更加棘手 - 我自己仍在研究中。虽然我猜他要么已经找到了解决方法,要么自从发布这个问题以来彻底改变了他的方法:p。 - CyberDandy
@CyberDandy 您是正确的,表视图头部视图确实有不同的行为。 - petehare
这就是为什么应该附带链接回答的原因。链接已经失效了,我要给它点个踩。现在七个赞也不值什么了。当链接恢复或者添加了某种形式的回答时,我会再次点赞。 - Nuno Gonçalves
2
你关于发布带有链接的内容是正确的,但如果你真的需要它,这里是链接:http://web.archive.org/web/20160326225445/http://blog.domesticcat.com.au/ios/2014/03/19/creating-parallax-effect-on-uiscrollview-using-simple-constraints/ - Edgar
OP正在寻求一个表头视图,你的回答并不完全相关。 - Happiehappie

5
首先,您应该从标题中删除 UIImageView 并将其作为简单的 UIImageView 添加到 UITableView 顶部。然后,由于 UITableViewDelegate 协议符合 UIScrollViewDelegate 协议,因此您可以实现 scrollViewDidScroll: 方法来检查 tableView 何时向下滚动并具有 bouncing 效果。例如:
-(void)someInitMethod {
   initialFrame = yourHeaderView.frame;
}
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
    if(scrollView.contentOffset.y < 0) {
       initialFrame.size.height -= scrollView.contentOffset.y;
       yourHeaderView.frame = initialFrame;
    }
}

同时,请确保为您的 UIImageView 设置了正确的 contentMode。此外,我认为这种实现方式可能会产生反弹效果,但我不能确定,因为我现在无法测试它,但我认为这是一个不错的起点。


嘿,Dany,感谢你的时间!我已经按照你的建议尝试了一下。但是不知道为什么,当我向下拖动时,图像就会消失,而且永远不会再出现。虽然实现了弹跳效果,但我还是想请教一下你有什么建议吗?我已经更新了我的问题,以展示我所尝试的内容。 - KingPolygon
请检查 initialFrame.size.height -= scrollView.contentOffset.y; 这一行代码,我认为应该是 - 而不是 +,但我不确定。因此,请先在 scrollViewDidScroll 中检查图像视图的框架,然后如果一切正常,请检查是否需要在 imageView 上调用 setNeedsDisplay 以重新绘制图像。 - danypata
@user1886754,请查看我的评论。 - danypata
2
数学计算有误,这会导致它看起来很卡顿,因为它不断地加上更大的数字,而不是按差值递增。 - mskw

3
这是我实现它的方法,在我的情况下,我使用了位于顶部的地图视图:
  1. Create a View Controller in storyboard.
  2. Add a Table View and set the constraints to 0 from all sides.
  3. Add a Map View (or whatever view) below the Table View so that it will get rendered over the top. It will look like it is overlapping.
  4. Add constraints to the top left and right.
  5. In the view controller viewDidLoad add the following: tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0) where 200 is the height of the View. This will push the contents of the table view downwards.
  6. In the view controller add the following code, which resizes the view based on the scrolling:

    func scrollViewDidScroll(scrollView: UIScrollView) {
        var scrollOffset = scrollView.contentOffset.y
        var headerFrame = mapView.frame
        if (scrollOffset < 0) {
            // Adjust map
            headerFrame = CGRect(x: mapView.frame.origin.x,
                y: mapView.frame.origin.y,
                width: mapView.frame.size.width,
                height: -scrollOffset)
        } else {
            // Adjust map
            headerFrame = CGRect(x: mapView.frame.origin.x,
                y: mapView.frame.origin.y,
                width: mapView.frame.size.width,
                height: 0)
        }
        mapView.frame = headerFrame
    }
    
如果我可以从Storyboard设置contentInset,那么它会更加美观。

需要给表视图设置一个清晰的背景颜色 :) - IvanPavliuk

1
在这个页面上早期的解决方案在我需要它与章节标题和索引栏一起工作时给了我一些麻烦,所以我自己想出了下面的替代方案。请注意:我在我的项目中不使用自动布局,并且我只在iOS9+上进行了测试;
在您的项目的Storyboard中:
1. 在UIViewController中创建一个UITableView(或尝试使用UITableViewController)。 2. 将UIView放置在UITableView的顶部(但在其中),使其成为第一个单元格上方的表头。 3. 给这个表头视图一个所需的高度(比如200px),并将背景颜色设置为“Clear Color”。Clear Color很重要,视图需要是透明的。 4. 在表头UIView中再降下一个2nd UIView,并使其大小与其父视图相同。这将是实际的表头,因此可以随意给它任何颜色,设置图像视图或其他内容。 5. 将这个2nd UIView连接到你的UIViewController IBOutlet,在我的例子中我把它命名为“headerView”。
接下来,转到您的UIViewController.m:
- (void)viewDidLoad
{
    [super viewDidLoad];

    // Remove view from table header and place it in the background instead.
    [self.headerView removeFromSuperview];
    UIView *backgroundView = [UIView new];
    [backgroundView addSubview:self.headerView];
    self.tableView.backgroundView = backgroundView;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    /* Set initialScrollOffset ivar to start offset, because in my case
       the scroll offset was affected by the statusbar + navigation bar heights
       and the view controller's "extend edges under top bars" option. */
    initialScrollOffset = self.tableView.contentOffset.y;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    /* Modify headerView height only if the table content gets pulled
       beyond initial offset. */
    if (scrollView.contentOffset.y < initialScrollOffset) {
        CGRect frame = self.headerView.frame;
        frame.size.height = self.tableView.tableHeaderView.frame.size.height + -scrollView.contentOffset.y;
        self.headerView.frame = frame;
    }
}

我只需要这个实现来创建一个带有背景颜色和标签的可拉伸标题。但是,向此标题添加UIImageView应该很容易。
此外,步骤1到5当然是完全可选的。您可以编程方式创建标题视图或使用XIB。只要确保表格具有设置为所需标题高度相同的清除颜色标题视图,因为这将作为间距器保持单元格和部分标题在同一行即可。
编辑:
我找到了一种更干净的方法来完成这个任务;
1.按照上述说明在界面构建器中构建表头:1个UIView作为容器,其中嵌入了第二个UIView。
2.跳过上面的viewDidLoad代码,没有必要将UIView从其容器中拿出来,我们也不需要将其设置为表格背景。
3.将scrollViewDidScroll:方法更改为以下内容:

UIViewController.m:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
      if (scrollView.contentOffset.y < initialScrollOffset) {
           CGRect frame = self.headerView.frame;
           frame.size.height = self.tableView.tableHeaderView.frame.size.height - scrollView.contentOffset.y;
           frame.origin.y = self.tableView.tableHeaderView.frame.origin.y + scrollView.contentOffset.y;
           self.headerView.frame = frame;
    }
}

就是这样。与其他解决方案唯一的视觉差异是,内容现在会随着其余单元格一起向上滚动,而不是被它们覆盖。


1

0

我不知道这是否能帮到你..

将滚动代理设置为self。

然后实现以下内容:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    float scrollViewHeight = scrollView.frame.size.height;
    float scrollContentSizeHeight = scrollView.contentSize.height;
    float scrollOffset = scrollView.contentOffset.y;

    if (scrollOffset == 0)
    {
        // then we are at the top
    }
    else if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
    {
        // then we are at the end
        // Do what you need here 
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接