初始化时 UIScrollView 内容偏移量
UIScrollView Content Offset on Initialization
我们目前正在为我们的 iOS 应用程序使用较旧的代码库,并且 运行 遇到了一个奇怪的错误,其中 UIScrollViews 分页在初始化时不匹配,但只有在用户选择按钮后才会匹配更改视图。
预期结果:
我们得到的结果:
每个 ScrollView 都嵌套了三张幻灯片。我们像这样初始化 ScrollView:
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("DIScrollView", owner: self, options: nil)
contentView.frame = self.bounds
addSubview(contentView)
contentView.autoresizingMask = [.flexibleHeight,.flexibleWidth]
contentView.layer.borderColor = UIColor.white.cgColor
contentView.layer.borderWidth = 2.0
scrollView.delegate = self
setUpScrollViewer()
}
您可以看到我们调用设置 ScrollView 是这样完成的:
public func setUpScrollViewer() {
let slides = self.createSlides()
let defaultIndex = 1
scrollView.Initialize(slides: slides, scrollToIndex: defaultIndex)
pageControl.numberOfPages = slides.count
pageControl.currentPage = defaultIndex
}
现在每张幻灯片的所有内容都可用,我们想要处理这些内容,我们使用 ScrollView 扩展来做到这一点:
extension UIScrollView {
//this function adds slides to the scrollview and constraints to the subviews (slides)
//to ensure the subviews are properly sized
func Initialize(slides:[UIView], scrollToIndex:Int) {
//Take second slide to base size from
let frameWidth = slides[1].frame.size.width
self.contentSize = CGSize(width: frameWidth * CGFloat(slides.count), height: 1)
for i in 0 ..< slides.count {
//turn off auto contstraints. We will be setting our own
slides[i].translatesAutoresizingMaskIntoConstraints = false
self.addSubview(slides[i])
//pin the slide to the scrollviewers edges
if i == slides.startIndex {
slides[i].leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
} else { //pin each subsequent slides leading edge to the previous slides trailing anchor
slides[i].leadingAnchor.constraint(equalTo: slides[i - 1].trailingAnchor).isActive = true
}
slides[i].topAnchor.constraint(equalTo: self.topAnchor).isActive = true
slides[i].widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
slides[i].heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true
}
//the last slides trailing needs to be pinned to the scrollviewers trailing.
slides.last?.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
self.scrollRectToVisible(CGRect(x: frameWidth * CGFloat(scrollToIndex), y: 0, width: frameWidth, height: 1), animated: false)
}
}
我已经尝试手动设置 contentOffset 并且似乎没有对初始化进行任何调整。如果用户选择它隐藏的按钮,然后取消隐藏它以正确显示它而无需逻辑调整。给我的印象是这个问题在 init 上。
总结:
当主视图加载时,当我需要专注于第二张幻灯片时,scrollView 会向我显示索引中的第一张幻灯片。但是,如果用户隐藏然后取消隐藏 scrollView,它会按预期工作。
如何让 UIScrollView 实际加载和初始化更新 scrollView 以显示第二张幻灯片而不是在第一张幻灯片上初始化?
我的猜测是,所有这些代码都在布局系统定位视图之前运行,并且第一张幻灯片的框架是默认的 0 x 0 大小。当此视图自动布局的应用程序 returns 计算出此幻灯片的大小时,计算就可以进行了。
点击布局循环滚动到布局后的正确位置。也许重写 viewDidLayoutSubviews()
来检查它是否在初始布局中,然后设置滚动位置。
- 对您的 contentView 使用约束,而不是设置 frame 和 autoresizingMask。
- 在viewController之前调用
view.layoutIfNeeded()
scrollRectToVisible或setContentOffset(我更喜欢最后一个)
在主线程中使用
明确地尝试 运行 scrollRectToVisible
DispatchQueue.main.async {
}
我们目前正在为我们的 iOS 应用程序使用较旧的代码库,并且 运行 遇到了一个奇怪的错误,其中 UIScrollViews 分页在初始化时不匹配,但只有在用户选择按钮后才会匹配更改视图。
预期结果:
我们得到的结果:
每个 ScrollView 都嵌套了三张幻灯片。我们像这样初始化 ScrollView:
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("DIScrollView", owner: self, options: nil)
contentView.frame = self.bounds
addSubview(contentView)
contentView.autoresizingMask = [.flexibleHeight,.flexibleWidth]
contentView.layer.borderColor = UIColor.white.cgColor
contentView.layer.borderWidth = 2.0
scrollView.delegate = self
setUpScrollViewer()
}
您可以看到我们调用设置 ScrollView 是这样完成的:
public func setUpScrollViewer() {
let slides = self.createSlides()
let defaultIndex = 1
scrollView.Initialize(slides: slides, scrollToIndex: defaultIndex)
pageControl.numberOfPages = slides.count
pageControl.currentPage = defaultIndex
}
现在每张幻灯片的所有内容都可用,我们想要处理这些内容,我们使用 ScrollView 扩展来做到这一点:
extension UIScrollView {
//this function adds slides to the scrollview and constraints to the subviews (slides)
//to ensure the subviews are properly sized
func Initialize(slides:[UIView], scrollToIndex:Int) {
//Take second slide to base size from
let frameWidth = slides[1].frame.size.width
self.contentSize = CGSize(width: frameWidth * CGFloat(slides.count), height: 1)
for i in 0 ..< slides.count {
//turn off auto contstraints. We will be setting our own
slides[i].translatesAutoresizingMaskIntoConstraints = false
self.addSubview(slides[i])
//pin the slide to the scrollviewers edges
if i == slides.startIndex {
slides[i].leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
} else { //pin each subsequent slides leading edge to the previous slides trailing anchor
slides[i].leadingAnchor.constraint(equalTo: slides[i - 1].trailingAnchor).isActive = true
}
slides[i].topAnchor.constraint(equalTo: self.topAnchor).isActive = true
slides[i].widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
slides[i].heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true
}
//the last slides trailing needs to be pinned to the scrollviewers trailing.
slides.last?.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
self.scrollRectToVisible(CGRect(x: frameWidth * CGFloat(scrollToIndex), y: 0, width: frameWidth, height: 1), animated: false)
}
}
我已经尝试手动设置 contentOffset 并且似乎没有对初始化进行任何调整。如果用户选择它隐藏的按钮,然后取消隐藏它以正确显示它而无需逻辑调整。给我的印象是这个问题在 init 上。
总结: 当主视图加载时,当我需要专注于第二张幻灯片时,scrollView 会向我显示索引中的第一张幻灯片。但是,如果用户隐藏然后取消隐藏 scrollView,它会按预期工作。
如何让 UIScrollView 实际加载和初始化更新 scrollView 以显示第二张幻灯片而不是在第一张幻灯片上初始化?
我的猜测是,所有这些代码都在布局系统定位视图之前运行,并且第一张幻灯片的框架是默认的 0 x 0 大小。当此视图自动布局的应用程序 returns 计算出此幻灯片的大小时,计算就可以进行了。
点击布局循环滚动到布局后的正确位置。也许重写 viewDidLayoutSubviews()
来检查它是否在初始布局中,然后设置滚动位置。
- 对您的 contentView 使用约束,而不是设置 frame 和 autoresizingMask。
- 在viewController之前调用
view.layoutIfNeeded()
scrollRectToVisible或setContentOffset(我更喜欢最后一个)
在主线程中使用
明确地尝试 运行scrollRectToVisible
DispatchQueue.main.async {
}