【发布时间】:2016-07-10 12:41:46
【问题描述】:
严格遵循 this 教程,在 使用 UIScrollView 进行分页部分,我刚刚实现了一个 ScrollView 用作幻灯片,其中包含从以前的 UICollectionViewController 下载的照片。加载滚动视图时,它不能正常工作,因为我看到了这些:
相反,当我向后滑动图像时,它们会以正确的方式显示,每页一个。或者更好的是,当我在幻灯片中获得第 4 张图像时,这个问题就消失了,只有在这一点上,以下所有图像都是正确的,前一个也是正确的。这是一个影响前 2 或 3 张图像的问题。
此外幻灯片甚至不是从用户刚刚点击的UICollectionViewCell 开始,而是从第一个开始。你可以在这里阅读所有代码:
import Foundation
import UIKit
class PagedScrollViewController: UIViewController, UIScrollViewDelegate {
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var pageControl: UIPageControl!
/* This will hold all the images to display – 1 per page.
It must be set from the previous view controller in prepareforsegue() method:
it will be the array of downloaded images for that photo gallery */
var pageImages:[UIImage]!
/* position in array images of the first to be showed, i.e. the one the user has just tapped */
var firstToShow:Int!
var currentImageViewForZoom:UIImageView?
/* This will hold instances of UIImageView to display each image on its respective page.
It’s an array of optionals, because you’ll be loading the pages lazily (i.e. as and when you need them)
so you need to be able to handle nil values from the array. */
var pageViews:[UIImageView?] = []
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.delegate = self
self.scrollView.maximumZoomScale = 1.0
self.scrollView.zoomScale = 10.0
self.pageControl.numberOfPages = self.pageImages.count
self.pageControl.currentPage = self.firstToShow
for _ in 0..<self.pageImages.count {
self.pageViews.append(nil)
}
/* The scroll view, as before, needs to know its content size.
Since you want a horizontal paging scroll view, you calculate the width to be the number of pages multiplied by the width of the scroll view.
The height of the content is the same as the height of the scroll view
*/
let pagesScrollViewSize = self.scrollView.frame.size
self.scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(self.pageImages.count),
height: pagesScrollViewSize.height)
// You’re going to need some pages shown initially, so you call loadVisiblePages()
self.loadVisiblePages()
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.currentImageViewForZoom
}
func scrollViewDidScroll(scrollView: UIScrollView) {
self.loadVisiblePages()
}
/*
Remember each page is a UIImageView stored in an array of optionals.
When the view controller loads, the array is filled with nil.
This method will load the content of each page.
1 - If it's outside the range of what you have to display, then do nothing
2 - If pageView is nil, then you need to create a page. So first, work out the frame for this page.
It’s calculated as being the same size as the scroll view, positioned at zero y offset,
and then offset by the width of a page multiplied by the page number in the x (horizontal) direction.
3 - Finally, you replace the nil in the pageViews array with the view you’ve just created,
so that if this page was asked to load again, you would now not go into the if statement and instead do nothing,
since the view for the page has already been created
*/
func loadPage(page: Int) {
if page < 0 || page >= self.pageImages.count {
//1
return
}
//2
if let _ = self.pageViews[page] {/*Do nothing. The view is already loaded*/}
else {
// 2
var frame = self.scrollView.bounds
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0.0
let newPageView = UIImageView(image: self.pageImages[page])
newPageView.contentMode = .ScaleAspectFit
newPageView.frame = frame
self.scrollView.addSubview(newPageView)
// 3
self.pageViews[page] = newPageView
self.currentImageViewForZoom = newPageView
}
}
/*
This function purges a page that was previously created via loadPage().
It first checks that the object in the pageViews array for this page is not nil.
If it’s not, it removes the view from the scroll view and updates the pageViews array with nil again to indicate that this page is no longer there.
Why bother lazy loading and purging pages, you ask?
Well, in this example, it won’t matter too much if you load all the pages at the start, since there are only five and they won’t be large enough to eat up too much memory.
But imagine you had 100 pages and each image was 5MB in size. That would take up 500MB of memory if you loaded all the pages at once!
Your app would quickly exceed the amount of memory available and be killed by the operating system.
Lazy loading means that you’ll only have a certain number of pages in memory at any given time.
*/
func purgePage(page: Int) {
if page < 0 || page >= self.pageImages.count {
// If it's outside the range of what you have to display, then do nothing
return
}
// Remove a page from the scroll view and reset the container array
if let pageView = self.pageViews[page] {
pageView.removeFromSuperview()
self.pageViews[page] = nil
}
}
func loadVisiblePages() {
// First, determine which page is currently visible
let pageWidth = self.scrollView.frame.size.width
// floor() function will round a decimal number to the next lowest integer
let page = Int(floor((self.scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0))) /***/
// Update the page control
self.pageControl.currentPage = page
// Work out which pages you want to load
let firstPage = page - 1
let lastPage = page + 1
// Purge anything before the first page
for var index = 0; index < firstPage; ++index {
self.purgePage(index)
}
// Load pages in our range
for index in firstPage...lastPage {
self.loadPage(index)
}
// Purge anything after the last page
for var index = lastPage+1; index < self.pageImages.count; ++index {
self.purgePage(index)
}
}
}
我想问题可能出在/***/ 上,这是我从教程中没有理解的内容。感谢您的关注
更新
在这里寻找类似的帖子,有人建议在viewDidLayoutSubviews() 中创建子视图,所以这是我刚刚尝试过的:
override func viewDidLayoutSubviews() {
self.loadVisiblePages()
}
现在图像已正确显示,前 3 张图像不再有那种奇怪的效果。但是为什么?我是一名初级 iOS 开发人员,但我仍然不知道所有这些要覆盖的方法以及它们的工作顺序。无论如何,仍然存在的另一个问题是图像总是从第一张开始显示,即使点击另一张图像也是如此。例如,看看这个:
即使点击另一个图像,也始终显示第一张图像(左上角)。最后,在我的代码中,我实现了具有缩放功能的委托方法,但它也不起作用。
更新 2
这是用户点击单元格时prepareForSegue() 的代码,来自之前的UICollectionViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toSlideShow") {
let pagedScrollViewController:PagedScrollViewController = segue.destinationViewController as! PagedScrollViewController
pagedScrollViewController.pageImages = self.imagesDownloaded
pagedScrollViewController.firstToShow = self.collectionView?.indexPathsForSelectedItems()![0].row
}
}
【问题讨论】:
-
要使用 UIScrollView 进行缩放,您需要设置滚动视图的 minimumZoomScale。您需要将代码移动到 viewDidLayoutSubviews 的原因是因为您正在使用自动布局,并且在自动布局引擎修改视图控制器的框架之前调用了 viewDidLoad。如果您在 viewDidLoad 中打印 self.view.frame,您通常会看到 0,0,600,600,因为这是故事板中的默认大小。把
self.scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(self.pageImages.count), height: pagesScrollViewSize.height)弄错了。 -
在 prepareForSegue 中发布代码,以便通过点击一个单元格启动 segue。
-
@beyowulf 我刚刚通过添加您询问的代码更新了我的问题。希望它的格式很好,因为我已经用智能手机进行了编辑,因为现在我不在办公室......真的谢谢你
-
当你点击任何单元格时,它是否仍在加载单元格[0]中的第一张图片?
-
@whereisleo 是的,正如你所说。如果我必须诚实,我还没有理解教程中计算页面的公式(带有/ *** /的行)。在我看来,问题可能就在那里。
标签: ios xcode swift uicollectionview scrollview