UIScrollView 或 UICollectionView 按从 firebase 调用的顺序滑动图像?

UIScrollView or UICollectionView to swipe through images in order called from firebase?

我的应用程序有一个功能,您可以在其中回答有关您关注的人的问题,例如(选项 A、B、C、D 是用户姓名所在的位置):

这个想法是你回答一个关于用户的问题,然后它从你从 firebase 数据库中关注的人中随机洗牌。这些图片是用户在注册时上传的个人资料图片,它们按照从左上角、右上角、左下角、右下角的顺序显示在问题的答案中。

我正在尝试使用 UIScrollView,但所有图像都堆叠在一起,无法在它们之间滑动(并且问题标签已消失)

有没有办法让 ScrollView 工作,或者有没有 better/more 集成 UICollectionView 的有效方法(我看到一些帖子推荐这个用于类似的事情)?

我是新手,非常感谢任何帮助,在此先感谢:)


更新:

我编辑了约束,使图像视图的左右锚点应该正确,并在故事板上的 UIScrollView 顶部添加了一个 UIView。我还看到它可以用 UIPageViewController 来完成?

@IBOutlet weak var userImageScrollView: UIScrollView!
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var questionLabel: UILabel!
@IBOutlet weak var optionA: UIButton!
@IBOutlet weak var optionB: UIButton!
@IBOutlet weak var optionC: UIButton!
@IBOutlet weak var optionD: UIButton!

func setupLayout() {
    userImageScrollView.isPagingEnabled = true
    userImageScrollView.isScrollEnabled = true

    userImageScrollView.addSubview(imageViewA)
    imageViewA.translatesAutoresizingMaskIntoConstraints = false
    imageViewA.widthAnchor.constraint(equalTo: userImageScrollView.widthAnchor).isActive = true
    imageViewA.heightAnchor.constraint(equalTo: userImageScrollView.heightAnchor).isActive = true
    imageViewA.topAnchor.constraint(equalTo: userImageScrollView.topAnchor).isActive = true
    imageViewA.bottomAnchor.constraint(equalTo: userImageScrollView.bottomAnchor).isActive = true
    imageViewA.leftAnchor.constraint(equalTo: userImageScrollView.leftAnchor)
    imageViewA.rightAnchor.constraint(equalTo: imageViewB.leftAnchor)
    imageViewA.contentMode = .scaleAspectFit

    userImageScrollView.addSubview(imageViewB)
    imageViewB.translatesAutoresizingMaskIntoConstraints = false
    imageViewB.widthAnchor.constraint(equalTo: userImageScrollView.widthAnchor).isActive = true
    imageViewB.heightAnchor.constraint(equalTo: userImageScrollView.heightAnchor).isActive = true
    imageViewB.bottomAnchor.constraint(equalTo: userImageScrollView.bottomAnchor).isActive = true
    imageViewB.leftAnchor.constraint(equalTo: imageViewA.rightAnchor)
    imageViewA.rightAnchor.constraint(equalTo: imageViewC.leftAnchor)
    imageViewB.contentMode = .scaleAspectFit

    userImageScrollView.addSubview(imageViewC)
    imageViewC.translatesAutoresizingMaskIntoConstraints = false
    imageViewC.widthAnchor.constraint(equalTo: userImageScrollView.widthAnchor).isActive = true
    imageViewC.heightAnchor.constraint(equalTo: userImageScrollView.heightAnchor).isActive = true
    imageViewC.bottomAnchor.constraint(equalTo: userImageScrollView.bottomAnchor).isActive = true
    imageViewC.leftAnchor.constraint(equalTo: imageViewB.rightAnchor)
    imageViewC.rightAnchor.constraint(equalTo: imageViewD.leftAnchor)
    imageViewC.contentMode = .scaleAspectFit

    userImageScrollView.addSubview(imageViewD)
    imageViewD.translatesAutoresizingMaskIntoConstraints = false
    imageViewD.widthAnchor.constraint(equalTo: userImageScrollView.widthAnchor).isActive = true
    imageViewD.heightAnchor.constraint(equalTo: userImageScrollView.heightAnchor).isActive = true
    imageViewD.bottomAnchor.constraint(equalTo: userImageScrollView.bottomAnchor).isActive = true
    imageViewD.leftAnchor.constraint(equalTo: imageViewC.rightAnchor)
    imageViewD.rightAnchor.constraint(equalTo: userImageScrollView.rightAnchor)
    imageViewD.contentMode = .scaleAspectFit

    self.userImageScrollView.delegate = self
}

是的,您可以使用 CollectionView 并 pagingnation.just 启用 CollecitonView 的分页选项。

1.Add 水平 Collection 在您视图的顶部区域中查看。启用分页选项 来自 属性 选择器。

  1. 将 CollectionView 单元格拖到 CollectionView 中。调整单元格大小以填充 整个 Collection查看
  2. 将图像添加到单元格

  3. 设置委托和数据源。

https://medium.com/@shaibalassiano/tutorial-horizontal-uicollectionview-with-paging-9421b479ee94

您的 imageView 彼此重叠的原因是您定义的:

 imageViewB.leftAnchor.constraint(equalTo: imageViewA.leftAnchor)

这意味着:imageView B 的左侧与 imageViewA 的左侧相同,本质上是说它们的左侧都从同一位置开始,因此它们将彼此重叠。

因此您需要从左到右定义每个项目:

imageViewB.leftAnchor.constraint(equalTo: imageViewA.rightAnchor)

imageViewBs 左侧,从 imageViewA 右侧开始。 imageView Cs leftAnchor 将等于 imageViewBs right 等等,直到到达最终的 imageViewD,您需要让 leftAnchor 等于 imageViewCs rightAnchor 和 imageViewDs rightAnchor 等于 scrollViews rightAnchor 以允许滚动正常工作。

如果您想向下滚动而不是从左向右滚动而不是左右锚点,您也可以使用 scrollView 轻松地做您想做的事情,使用 centerXAnchors 使视图在 scrollView

你需要想象你正在向某人描述布局,ImageViewA 在顶部,所以它的顶部锚点等于 scrollViews 顶部锚点。

对于 imageViewB,您可以从上到下进行相同的描述,因此:

 imageViewB.topAnchor.constraint(equalTo: imageViewA.bottomAnchor).isActive = true

图像视图 B 的顶部从图像视图 A 的底部开始,然后您对其余部分执行相同操作,如下所示:

 imageViewC.topAnchor.constraint(equalTo: imageViewC.bottomAnchor).isActive = true

 imageViewD.topAnchor.constraint(equalTo: imageViewC.bottomAnchor).isActive = true

因为它是一个scrollView,而你是向下滚动的,top(imageViewA)需要设置到scroll view的顶部,另外bottom item需要定义它的bottomAnchor到scrollView的底部滚动正确工作的顺序:

  imageViewD.bottomAnchor.constraint(equalTo: userImageScrollView.bottomAnchor).isActive = true 

您还在某些视图中同时使用 centerXAnchorleftAnchor,假设 centerXAnchorleftAnchor 相同,只是从不同的角度描述它视图的一部分,因为您的 centerXAnchor 在 leftAnchor 之后,它将只使用 centerX,这意味着图像将在 scrollView 中居中。

我建议遵循此模式并从头开始重新构建您的约束,真正关注需要定义的锚点和位置。您也可以使用 Interface Builder 来添加视图,但是学习像这样定义约束将在未来被证明是一项非常有价值的技能,并且有助于保持您的代码非常清晰和干净。

更新:

此代码将完全按照您的要求执行,请注意滚动视图的高度和宽度以及我用来提供 space 的常量。每个 imageView 都按照我上面所说的方式定义,从左到右,最后一个项目具有左右约束。删除您的 setupLayout 并将其替换为这个(确保在必要时更改约束以适合您的应用程序):

 func setupLayout() {
    view.addSubview(scrollView)
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50).isActive = true
    scrollView.heightAnchor.constraint(equalToConstant: 300).isActive = true
    scrollView.widthAnchor.constraint(equalToConstant: 300).isActive = true
    scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    scrollView.backgroundColor = .gray
    scrollView.isPagingEnabled = true

    scrollView.addSubview(imageViewA)
    imageViewA.translatesAutoresizingMaskIntoConstraints = false

    imageViewA.widthAnchor.constraint(equalToConstant: 250).isActive = true
    imageViewA.heightAnchor.constraint(equalToConstant: 250).isActive = true

    imageViewA.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
    imageViewA.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 25).isActive = true

    imageViewA.backgroundColor = .cyan

    scrollView.addSubview(imageViewB)
    imageViewB.translatesAutoresizingMaskIntoConstraints = false

    imageViewB.heightAnchor.constraint(equalToConstant: 250).isActive = true
    imageViewB.widthAnchor.constraint(equalToConstant: 250).isActive = true


    imageViewB.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
    imageViewB.leftAnchor.constraint(equalTo: imageViewA.rightAnchor, constant: 25).isActive = true

    imageViewB.backgroundColor = .red

    scrollView.addSubview(imageViewC)
    imageViewC.translatesAutoresizingMaskIntoConstraints = false

    imageViewC.heightAnchor.constraint(equalToConstant: 250).isActive = true
    imageViewC.widthAnchor.constraint(equalToConstant: 250).isActive = true


    imageViewC.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
    imageViewC.leftAnchor.constraint(equalTo: imageViewB.rightAnchor, constant: 25).isActive = true

    imageViewC.backgroundColor = .black

    scrollView.addSubview(imageViewD)
    imageViewD.translatesAutoresizingMaskIntoConstraints = false

    imageViewD.heightAnchor.constraint(equalToConstant: 250).isActive = true
    imageViewD.widthAnchor.constraint(equalToConstant: 250).isActive = true


    imageViewD.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
    imageViewD.leftAnchor.constraint(equalTo: imageViewC.rightAnchor, constant: 25).isActive = true
    imageViewD.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -25).isActive = true

    imageViewD.backgroundColor = .green


}

这是该代码的作用的 gif:

via GIPHY

  • 别忘了在viewDidLoad()

    中调用setupLayout
     override func viewDidLoad() {
    super.viewDidLoad()
    
    setupLayout()
    // Do any additional setup after loading the view, typically from a nib.
     }