使用 UIScrollView 循环浏览图像

Posted

技术标签:

【中文标题】使用 UIScrollView 循环浏览图像【英文标题】:Using UIScrollView to cycle through images 【发布时间】:2015-06-29 14:16:19 【问题描述】:

我在 scrollView 中有一个 imageView,我希望能够上传最多 3 张图片并让用户在它们之间滑动。我只是通过用我想要的信息替换视图的内容来实现这一点,但它看起来或感觉不如带有分页的滚动视图。

我有所有代码可以让每个图像在我想要的时候出现,但我的问题是滚动视图约束以及如何向具有固定宽度的滚动视图添加更多内容。无论我做什么,当我将图像添加到视图时,我似乎都无法扩展滚动范围。

这是我现在正在尝试的:

let newImageView:UIImageView = UIImageView()
self.imageScrollView.contentSize = CGSize(width: self.imageView.frame.size.width * 3, height: self.imageView.frame.size.height)
self.imageScrollView.pagingEnabled = true

for i = 0; i < 3; ++i 
    var xOrigin:CGFloat = CGFloat(i) * self.view.frame.size.width
    newImageView.frame = CGRectMake(self.imageView.image!.size.width * i, 0, self.imageView.image!.size.width, self.imageScrollView.frame.size.height)
    newImageView.image = images[i]
    newImageView.contentMode = UIViewContentMode.ScaleAspectFit
    self.imageScrollView.addSubview(newImageView)

使用此代码,我可以添加图像,但无法滚动到它们。在我的故事板中,滚动视图约束如下所示:

我确信其中一些约束是多余的,但我无法弄清楚为什么内容宽度不会扩展并允许我滚动浏览滚动视图中的所有图像。

编辑

我使用来自@matt 的教科书示例进行了更改。我制作了一个新的视图控制器并将其放在另一个视图控制器的视图中(与我最初的相同)。它显示第一个没问题,但是当我向左或向右滑动时,它似乎没有调用 UIPageViewControllerDataSource 函数。我不确定为什么会这样。

这是原始视图控制器 (UploadPhotoViewController) 中的样子

func setUpPageViewController() 
    sharedIm.images.append(UIImage(named: "placeholder")!)
    sharedIm.images.append(UIImage(named: "TestProfile")!)
    sharedIm.images.append(UIImage(named: "button")!)
    let pvc = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
    let page:ImagePage = ImagePage()
    pvc.dataSource = self
    pvc.setViewControllers([page], direction: .Forward, animated: false, completion: nil)

    pvc.view.frame = self.imageContainer.bounds
    self.imageContainer.addSubview(pvc.view)
    pvc.didMoveToParentViewController(self)


//this is placed at the end of the class
extension UploadPhotoViewController : UIPageViewControllerDataSource 
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? 
    let image = (viewController as! ImagePage).image
    let ix = find(sharedIm.images, image)! + 1
    println(ix)
    if ix >= sharedIm.images.count 
        println("no next page")
        return nil
    
    sharedIm.currentIndex = ix
    let page = ImagePage()
    return page



func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? 
    let image = (viewController as! ImagePage).image
    let ix = find(sharedIm.images, image)! - 1
    println(ix)
    if ix < 0 
        println("no previous page")
        return nil
    
    sharedIm.currentIndex = ix
    let page = ImagePage()
    return page

这是我的新视图控制器中添加到另一个视图中的内容:

class ImagePage: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate 

var image : UIImage? 
var imagePicker: UIImagePickerController!
@IBOutlet var imageView : UIImageView!
@IBOutlet var forwardButton: UIButton!
@IBOutlet var backButton: UIButton!
@IBOutlet var closeButton: UIButton!
@IBOutlet var pictureButton: UIButton!
@IBOutlet var cameraButton: UIButton!



init() 
    self.image = sharedIm.images[sharedIm.currentIndex]
    super.init(nibName: "ImagePage", bundle: nil)


required init(coder: NSCoder) 
    fatalError("NSCoding not supported")


override func viewDidLoad() 
    super.viewDidLoad()
    self.imageView.image = self.image

//bunch of other code for buttons and uploading pictures

【问题讨论】:

【参考方案1】:

使用 UIPageViewController (带有滚动样式),您尝试做的事情会容易得多。我建议您改用 UIPageViewController 实现。

原因是您一次只提供 一个“页面”(在您的情况下是图像)。您可以实时决定在任一方向上是否有另一个“页面”,以及您想假装“真的”有多少“页面”。簿记工作发生在您的模型中(幕后的数据),而不是像 UIScrollView 那样,您必须配置整个视图来一次处理所有页面。

【讨论】:

谢谢!所以在我的情况下,最好将一个容器(尺寸正确)添加到我现有的视图控制器中,然后将 UIPageViewController 添加到容器中? 完全正确 - 很抱歉,该示例没有说明这一点。这是一个:github.com/mattneub/Programming-ios-Book-Examples/blob/master/… 很抱歉,如果这看起来很无聊,但我无法弄清楚为什么 UIPageViewControllerDataSource 函数没有被调用。我用根据您的示例改编的新代码更新了我的问题。顺便说一句,你的教科书例子太棒了!我在其中看到了几个很酷的例子,我已经/将用它们作为重构我已经做过的事情的想法(因为我根本不知道我在做 iOS 开发做什么) 你的代码看起来不错;我可能必须查看您的项目才能了解手势问题。您确定甚至没有调用这些方法吗?这听起来像是手势甚至没有被传达给页面视图控制器。您是否为 self.imageContainer 启用了用户交互? 想通了!我正在将 pvc.view 添加到 self.imageContainer 的子视图中,但我没有做 self.addChildViewController(pvc)【参考方案2】:

使用自动布局和 uiscrollview 时,诀窍是知道何时加载您的内容。由于您在混合模式(框架和自动布局)下工作,您需要确保约束有时间加载,然后在加载后,您可以添加子视图并调整约束。如果您尝试在 viewDidLoad 上加载内容,则为时过早,您的约束可能尚未设置。如果您在 viewWillAppear 上加载您的内容,那么为时已晚,并且约束已经被锁定以向用户呈现视图。

所以,我发现加载内容的最佳位置是viewDidLayoutSubviews。此时,自动布局已将约束应用于您的滚动视图,您现在可以安全地进行更改。在此处添加调用以运行填充 scrollView 的代码,您应该没问题。此外,您需要设置一个标志以仅进行一次调用,因为 viewDidLayoutSubviews 在视图创建期间可能会被调用多次。您还应该在 scrollView 上调用 setNeedsUpdateConstraints 以确保在添加子视图时更新其约束。

【讨论】:

以上是关于使用 UIScrollView 循环浏览图像的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历 UIScrollView 并设置 UImageView

循环浏览本地文件夹并动态创建元素

如何配置 UIScrollView 使可见区域永远不会超出背景图像?

uiscrollview 中的图像显示

带有图像的 UIScrollView

带有背景图像的 UIScrollView