gpt4 book ai didi

ios - 仅当 style 设置为 'Scroll' 时,UIPageViewController 中的约束异常

转载 作者:行者123 更新时间:2023-11-29 05:37:14 26 4
gpt4 key购买 nike

我使用 UIPageView 允许用户滚动浏览图像集合,当 UIPageViewController 设置为 Scroll 时,出现约束错误(没有共同祖先) code> 过渡样式,但设置为 Page Curl 时则不然。

到目前为止,我已经尝试将抛出错误的约束的 anchor (我已经准确地确定了罪魁祸首)更改为不同的东西(尝试了Safe AreaSuperview),但没有任何改变。我对 Swift 比较陌生,并且不太了解 UIPageViewController 的工作原理,因此很有可能我只是以错误的顺序调用事物而没有意识到这一点。我有点困惑,为什么错误发生在 Scroll 过渡样式而不是 Page Curl 上,因为在我看来,它们应该类似地工作...还对为什么约束 anchor 锚定到自己的 super View 时不在同一 View 层次结构中感到困惑?

这是 UIPageViewController 委托(delegate):

class ImageDetailPageViewController: UIPageViewController {

// MARK: Properties

var images: [UIImage]!
var index: Int!

var navbarHeight: CGFloat!

fileprivate lazy var pages: [UIViewController] = {
return getPages()
}()

// MARK: Methods

override func viewDidLoad() {
super.viewDidLoad()

self.dataSource = self
self.delegate = self

self.view.translatesAutoresizingMaskIntoConstraints = false

setViewControllers([pages[index]], direction: .forward, animated: true, completion: nil)
}

override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}

// MARK: Methods

fileprivate func getPages() -> [ImageView] {
var pages = [ImageView]()

let storyboard = UIStoryboard(name: "ImageDetail", bundle: nil)

for image in images {
let imageDetail = storyboard.instantiateViewController(withIdentifier: "ImageDetail") as! ImageView
imageDetail.image = image

pages.append(imageDetail)
}

return pages
}
}

// MARK: Extensions

extension ImageDetailPageViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = pages.firstIndex(of: viewController) else {
return nil
}

let previousIndex = viewControllerIndex - 1

guard previousIndex >= 0 else {
return pages.last
}

guard pages.count > previousIndex else {
return nil
}

return pages[previousIndex]
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let viewControllerIndex = pages.firstIndex(of: viewController) else {
return nil
}

let nextIndex = viewControllerIndex + 1

guard nextIndex < pages.count else {
return pages.first
}

guard pages.count > nextIndex else {
return nil
}

return pages[nextIndex]
}

func presentationCount(for pageViewController: UIPageViewController) -> Int {
return pages.count
}

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return index
}
}

extension ImageDetailPageViewController: UIPageViewControllerDelegate { }

页面 View 中的 View Controller (ImageDetail)非常简单。它由锚定到安全区域UIScrollView和锚定到UIScrollViewUIImageView组成。

当我尝试滚动到页面 View 中的下一页时,应用程序崩溃,并抛出以下错误:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x600001b72400 "UIImageView:0x7ff44c56caf0.top"> and <NSLayoutYAxisAnchor:0x600001b77e40 "UIScrollView:0x7ff44d164800.top"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal.'

当设置为Page Curl时,它工作得很好。当在页面 View 之外自行加载时, View Controller 也可以完美呈现。

编辑:以下是 ImageDetail View 的代码:

class ImageView: UIViewController, UIScrollViewDelegate {

// MARK: Properties

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet var zoomGestureRecognizer: UITapGestureRecognizer!

// imageView contraints
@IBOutlet var imageViewBottomConstraint: NSLayoutConstraint!
@IBOutlet var imageViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet var imageViewTopConstraint: NSLayoutConstraint!
@IBOutlet var imageViewTrailingConstraint: NSLayoutConstraint!

var image: UIImage!

// MARK: Overrides

override func viewDidLoad() {
super.viewDidLoad()

// set the image
if let image = image {
imageView.image = image
} else {
// log error
os_log("Error. Image Detail opened without an image loaded.", log: OSLog.default, type: .error)

// dismiss view
self.dismiss(animated: false, completion: nil)
}

// assume scrollView delegate
scrollView.delegate = self
scrollView.maximumZoomScale = 2

// set imageView snapshot mode
imageView.snapshotView(afterScreenUpdates: true)
}

override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()

updateMinZoomScaleForSize(view.compatibleSafeAreaLayoutGuide.layoutFrame.size)
updateConstraintsForSize(view.compatibleSafeAreaLayoutGuide.layoutFrame.size)
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: false)
}

// MARK: Methods

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {
updateConstraintsForSize(view.compatibleSafeAreaLayoutGuide.layoutFrame.size)
}

fileprivate func updateConstraintsForSize(_ size: CGSize) {
let yOffset = max(0, (view.compatibleSafeAreaLayoutGuide.layoutFrame.height - imageView.frame.height) / 2)
imageViewTopConstraint.constant = yOffset
imageViewBottomConstraint.constant = yOffset

let xOffset = max(0, (view.compatibleSafeAreaLayoutGuide.layoutFrame.width - imageView.frame.width) / 2)
imageViewLeadingConstraint.constant = xOffset
imageViewTrailingConstraint.constant = xOffset

// activate constraints
imageViewTopConstraint.isActive = true
imageViewBottomConstraint.isActive = true
imageViewLeadingConstraint.isActive = true
imageViewTrailingConstraint.isActive = true

view.layoutIfNeeded()
}

fileprivate func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = view.compatibleSafeAreaLayoutGuide.layoutFrame.width / imageView.bounds.width
let heightScale = view.compatibleSafeAreaLayoutGuide.layoutFrame.height / imageView.bounds.height
let minScale = min(widthScale, heightScale)

scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
}

fileprivate func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect {
// create and size view window
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height
zoomRect.size.width = imageView.frame.size.width

// center on tapped point
let newCenter = imageView.convert(center, from: view)
zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)

// return rect
return zoomRect
}

// MARK: Actions

@IBAction func tapToZoom(_ sender: UITapGestureRecognizer) {
if scrollView.zoomScale == scrollView.minimumZoomScale {
scrollView.zoom(to: zoomRectForScale(scrollView.maximumZoomScale, center: zoomGestureRecognizer.location(in: zoomGestureRecognizer.view)), animated: true)
} else {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
}
}
}

以及相应的 Storyboard: Storyboard screenshot

最佳答案

知道这一行 imageView.snapshotView(afterScreenUpdates: true) 明确告诉渲染 UIImageView 的外观,如果失败,则快照可能不可见内容。

我不确定您想要实现什么目标,但注释掉该行肯定会解决您的问题。如果您需要任何帮助来呈现您想要的 UI 或其他内容,请告诉我。

阅读官方documentation了解更多详情。

关于ios - 仅当 style 设置为 'Scroll' 时,UIPageViewController 中的约束异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56928916/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com