Ios 更新约束子视图时UIScrollView行为异常
我在XIB中制作了一个Ios 更新约束子视图时UIScrollView行为异常,ios,swift,uiscrollview,xib,Ios,Swift,Uiscrollview,Xib,我在XIB中制作了一个UIScrollView,用于我的入职培训。UIScrollView有3个入职视图。长话短说: 这很好用。但是,当第三页/最后一页在屏幕上时,我希望左上和右上的按钮(Overslaan-Volgende)在屏幕上/下设置动画。当我设置按钮的动画时,我的UIScrollView开始表现出奇怪的行为: 这是我使用的代码: func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity veloc
UIScrollView
,用于我的入职培训。UIScrollView
有3个入职视图。长话短说:
这很好用。但是,当第三页/最后一页在屏幕上时,我希望左上和右上的按钮(Overslaan-Volgende)在屏幕上/下设置动画。当我设置按钮的动画时,我的UIScrollView开始表现出奇怪的行为:
这是我使用的代码:
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)
}
func-scrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
让pageIndex=Int(targetContentOffset.pointee.x/self.frame.width)
pageControl.currentPage=pageIndex
如果stepViews[pageIndex]正在登录LoginView{
moveControlConstraintsOffScreen()
}否则{
MoveControlConstraintsOn屏幕()
}
UIView.animate(持续时间:0.5,延迟:0,使用SpringWithDamping:1,初始SpringVelocity:1,选项:.curveEaseOut,动画:{
self.layoutifneed()
},完成日期:无)
}
我调试了代码,结果表明,无论动画块如何,为约束设置新常量都会导致问题。如何使按钮在屏幕上向上/向外移动而不使我的scrollView行为怪异?触发布局过程似乎会干扰您的scroll view定位。您可以实现
func-scrollViewDidScroll(\uScrollView:UIScrollView)
,并尝试按帧更新按钮视图,而无需更改自动布局约束。对于自动布局之外的帧更改,我通常使用transform
属性,因为对frame
或bounds
的任何更改都会在下一个布局过程中被覆盖
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来确定页面的滚动距离。
是的,这涉及到查看视图层次结构内部,但苹果已经五年没有改变它了,所以你应该是安全的。巧合的是,我上周实际实施了这种方法,它的效果非常好。
如果你感兴趣,我可以进一步扩展这个话题。可以找到为我指出正确方向的帖子。触发布局过程似乎干扰了您的滚动视图定位。您可以实现
func-scrollViewDidScroll(\uScrollView:UIScrollView)
,并尝试按帧更新按钮视图,而无需更改自动布局约束。对于自动布局之外的帧更改,我通常使用transform
属性,因为对frame
或bounds
的任何更改都会在下一个布局过程中被覆盖
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来确定页面的滚动距离。
是的,这涉及到查看视图层次结构内部,但苹果已经五年没有改变它了,所以你应该是安全的。巧合的是,我上周实际实施了这种方法,它的效果非常好。
如果你感兴趣,我可以进一步扩展这个话题。可以找到为我指明正确方向的帖子。我就是这么做的
我不能发布图片,你可以看看这个
这就是代码
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)
}
var centerYConstraint:约束!
func setupConstraint(){
fadeView.snp.makeConstraints{make in
make.centerX.equalToSuperview()
centerYConstraint=make.centerY.equalToSuperview().constraint
制造尺寸相等(CGSize(宽:50,高:50))
}
}
func ScrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
让pageIndex=Int(targetContentOffset.pointee.x/self.view.frame.width)
如果pageIndex!=1{
centerYConstraint.update(偏移量:self.view.frame.height)
}否则{
centerYConstraint.update(偏移量:0)
}
UIView.animate(持续时间:0.5,延迟:0,使用SpringWithDamping:1,初始SpringVelocity:1,选项:.curveEaseOut,动画:{
self.view.layoutifneed()
},完成日期:无)
}
以下是我的工作
我不能发布图片,你可以看看这个
这就是代码
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)
}
var centerYConstraint:约束!
func setupConstraint(){
fadeView.snp.makeConstraints{make in
make.centerX.equalToSuperview()
centerYConstraint=make.centerY.equalToSuperview().constraint
制造尺寸相等(CGSize(宽:50,高:50))
}
}
func ScrollViewWillendDraging(scrollView:UIScrollView,withVelocity:CGPoint,targetContentOffset:UnsafemeutablePointer){
让pageIndex=Int(targetContentOffset.pointee.x/self.view.frame.width)
如果pageIndex!=1{
centerYConstraint.update(偏移量:self.view.frame.height)
}否则{
centerYConstraint.update(偏移量:0)
}
UIView.animate(持续时间:0.5,延迟:0,使用SpringWithDamping:1,初始SpringVelocity:1,选项:.curveEaseOut,动画:{
self.view.layoutifneed()
},完成日期:无)
}
根据@cloveleddy的回答,我做了两项修改:
1:看来layoutSubviews应该对这种奇怪的行为负责。要解决此问题,我阻止scrollView始终调用LayoutSubview:
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
}
}
基于