更新约束子视图时,UIScrollView表现得很奇怪

时间:2017-04-06 09:20:25

标签: ios swift uiscrollview xib

我在XIB中为我的入职制作了UIScrollViewUIScrollView有3个入职观点。长话短说:

correct

这很完美。但是,当屏幕上显示第三页/最后一页时,我希望左上和右上按钮(Overslaan - Volgende)为屏幕设置动画。当我关闭按钮动画时,我的UIScrollView开始表现得很奇怪:

wrong

这是我使用的代码:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

        let pageIndex = Int(targetContentOffset.pointee.x / self.frame.width)
        pageControl.currentPage = pageIndex

        if stepViews[pageIndex] is OnboardingLoginView {
            moveControlConstraintsOffScreen()
        } else {
            moveControlConstraintsOnScreen()
        }

        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            self.layoutIfNeeded()
        }, completion: nil)
    }

我调试了代码,事实证明,无论动画块如何,为约束设置新常量都会导致问题。如何在没有我的scrollView表现奇怪的情况下使按钮向上/向下移动屏幕?

3 个答案:

答案 0 :(得分:1)

看起来触发布局传递会干扰滚动视图定位。您可以实现func scrollViewDidScroll(_ scrollView: UIScrollView)并尝试在每帧的基础上更新按钮视图,而不更改自动布局约束。我通常使用transform属性进行自动布局之外的帧更改,因为在下一次布局过程中,framebounds的任何更改都会被覆盖。

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    guard mustBeOnLastPage else {
        buttonOne.tranform = .identity
        buttonTwo.tranform = .identity
        return
    }

    let offset = scrollView.contentOffset.x
    buttonOne.tranform = .init(translationX: 0, y: offset)
    buttonTwo.tranform = .init(translationX: 0, y: offset)
}

旧答案

这种解释与你所要求的有些相似。

因为看起来你在分页上下文中使用滚动视图,我会通过使用UIPageViewController来解决这个问题。由于UIPageViewController在内部使用UIScrollView,因此您可以观察滚动视图中最后一个视图的contentOffset,以确定页面滚动的距离。 是的,这涉及到查看视图层次结构,但Apple已经改变了五年,所以你应该保持安全。巧合的是,我上周实际上采用了这种方法,它就像一个魅力。 如果您有兴趣,我可以进一步扩展这个主题。可以找到指向正确方向的帖子here

答案 1 :(得分:1)

这是我做的事情

我无法发布图片,您可以查看此http://i.imgur.com/U7FHoMu.gif

这是代码

var centerYConstraint: Constraint!

func setupConstraint() {
    fadeView.snp.makeConstraints { make in
        make.centerX.equalToSuperview()
        centerYConstraint = make.centerY.equalToSuperview().constraint
        make.size.equalTo(CGSize(width: 50, height: 50))
    }
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint,targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let pageIndex = Int(targetContentOffset.pointee.x / self.view.frame.width)
    if pageIndex != 1 {
        centerYConstraint.update(offset: self.view.frame.height)
    } else {
        centerYConstraint.update(offset: 0)
    }

    UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { 
        self.view.layoutIfNeeded()
    }, completion: nil)
}

答案 2 :(得分:0)

根据@ CloakedEddy的回答,我做了两处修改:

1:似乎layoutSubviews负责奇怪的行为。为了解决这个问题,我阻止scrollView始终调用layoutSubviews:

override func layoutSubviews() {
    super.layoutSubviews()

    if !didLayoutSubviews {
        for index in 0..<stepViews.count {
            let page: UIView = stepViews[index]

            let xPosition = scrollView.frame.width * CGFloat(index)

            page.frame = CGRect(x: xPosition, y: 0, width: scrollView.bounds.width, height: scrollView.frame.height)

            scrollView.contentSize.width = scrollView.frame.width * CGFloat(index + 1)
        }

        didLayoutSubviews = true
    }
}

2:如果您要更新设备方向的视图:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    onboardingView.didLayoutSubviews = false
    onboardingView.setNeedsLayout()
}