【问题标题】:make UIView in UIScrollView stick to the top when scrolled up向上滚动时使 UIScrollView 中的 UIView 粘在顶部
【发布时间】:2012-07-01 15:18:48
【问题描述】:

因此,在 UITableView 中,当您有部分时,部分视图会粘在顶部,直到下一部分与其重叠,然后将其替换在顶部。我想要一个类似的效果,基本上我的 UIScrollView 中有一个 UIView,代表 UIView 部分以及它何时到达顶部。我希望它留在那里而不是被抬高。我该怎么做呢?我认为这需要在 layoutSubviews 或 scrollViewDidScroll 中完成,并对 UIVIew 进行操作..

【问题讨论】:

    标签: iphone objective-c ios ipad uiscrollview


    【解决方案1】:

    要在 UIScrollView 中创建 UIView 在向上滚动时粘在顶部,请执行以下操作:

    func createHeaderView(_ headerView: UIView?) {
        self.headerView = headerView
        headerViewInitialY = self.headerView.frame.origin.y
        scrollView.addSubview(self.headerView)
        scrollView.delegate = self
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let headerFrame = headerView.frame
        headerFrame.origin.y = CGFloat(max(headerViewInitialY, scrollView.contentOffset.y))
        headerView.frame = headerFrame
    }
    

    【讨论】:

    • 确保您打算为其捕获滚动的视图有一个委托集,并且该委托是 scrollViewDidScroll 所在的位置。如果您让控制器实现协议 ,您可以在控制器中将委托分配为“自我”,例如 this
    • 我试过了,它工作正常,但我的视图变得半透明,我尝试了一切但没有成功,所以请你帮我解决它发生的方式或原因。它只会在一段时间内变得半透明,直到它粘在顶部
    【解决方案2】:

    Evya 的解决方案效果很好,但是如果您使用 Auto Layout,则应该执行以下操作(Auto Layout 语法是用 Masonry 编写的,但您明白了。):

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
        //Make the header view sticky to the top.
        [self.headerView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(self.scrollView.mas_top).with.offset(scrollView.contentOffset.y);
            make.left.equalTo(self.scrollView.mas_left);
            make.right.equalTo(self.scrollView.mas_right);
    
            make.height.equalTo(@(headerViewHeight));
        }];
    
        [self.scrollView bringSubviewToFront:self.headerView];
    }
    

    【讨论】:

    • 不幸的是,这会迫使您在滚动移动的每一帧时重新创建布局约束。相反,你应该做的是让一个容器包含UIScrollView 并使标题的顶部等于 容器的 顶部,而不是滚动视图的顶部加上内容偏移量。这样做可以让您设置一次约束。
    • @AnthonyMills 感谢您的评论!帮助我理解了很多。
    【解决方案3】:

    基于 EVYA 响应的 Swift 解决方案:

    var navigationBarOriginalOffset : CGFloat?
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        navigationBarOriginalOffset = navigationBar.frame.origin.y
    }
    
    func scrollViewDidScroll(scrollView: UIScrollView) {
        navigationBar.frame.origin.y = max(navigationBarOriginalOffset!, scrollView.contentOffset.y)
    }
    

    【讨论】:

      【解决方案4】:

      如果我没记错的话,2010 WWDC ScrollView 演示文稿准确地讨论了如何将视图保持在固定位置,而其他元素围绕它滚动。观看视频,您应该有一个明确的实施方法。

      它本质上是基于 scrollViewDidScroll 回调来更新帧(虽然内存在细节上有点模糊)。

      【讨论】:

      • hmm.. 基本上你必须检查那个分段的 UIView 是否在顶部,然后把它放在那里对吗?我的问题是如何确定分段的 UIView 是否在“顶部”
      • 要确定哪个视图在顶部,您可以向超级视图询问它的子视图数组,例如NSArray *subviews = [超级视图子视图]。然后,向您的数组询问您要比较的子视图的索引,例如,NSUInteger oneIndex = [subviews indexOfObject:viewOne], twoIndex = [subviews indexOfObject:viewTwo]。找到两个子视图的索引后,只需评估哪个更大,以确定哪个在另一个之上。
      • 当我说在上面时,并不是指一个在彼此之上..但我的意思是在 contentOffSet.y
      • 对您的设计一无所知,很难准确地说您应该如何“知道”哪个是最重要的。我的想法是,视图控制器会根据为您的模型提供的部分信息或其他一些基础来判断哪个是“当前”部分。试图确定哪个部分/标题应该在视图范围内完全位于顶部(即,您可以通过比较 yOffsets 或 rectContainsRect 或类似方法来做到这一点),这似乎不是一个理想的策略。
      猜你喜欢
      • 2019-06-15
      • 1970-01-01
      • 2012-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多