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

标签 ios swift uiscrollview uicollectionview firebase-storage

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

How the page should look

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

我正在尝试使用 UIScrollView,但所有图像都堆叠在一起,而不是能够在它们之间滑动(并且问题标签消失了)

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

我是新手,所以希望得到任何帮助,在此先感谢:)


更新:

我已经编辑了约束,因此 ImageView 的左右 anchor 应该是正确的,并在 Storyboard上的 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
}

最佳答案

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

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

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

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

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

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

如果你想向下滚动而不是从左到右滚动,你也可以使用 scrollView 轻松地做你想做的事情,而不是左右 anchor ,使用 centerXAnchors 使 View 在 scrollView 中居中

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

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

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

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

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

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

因为它是一个 scrollView,而你正在向下滚动,top (imageViewA) 需要设置到 ScrollView 的顶部,另外 bottom item 需要将它的 bottomAnchor 定义到 scrollView 的底部,以便滚动以正常工作:

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

您还在某些 View 中同时使用了 centerXAnchorleftAnchor,假设 centerXAnchorleftAnchor 但只是从 View 的不同部分描述它,因为您的 centerXAnchor 位于 leftAnchor 之后,它只会使用 centerX,这意味着图像将在 scrollView 中居中。

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

更新:

此代码将完全按照您的要求执行,请注意 ScrollView 的高度和宽度以及我用来提供空间的常量。每个 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.
     }
    

关于ios - UIScrollView 或 UICollectionView 按从 firebase 调用的顺序滑动图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54984711/

相关文章:

ios - UITableView 加载缓慢

ios - iOS 推送通知中的多行标题

ios - 如何访问 NSIndexPath 部分值?

swift - 我可以在 launchImage 消失后淡出它吗?

ios - 覆盖 setContentOffset

ios - 从IOS通知中心一条条读取通知后如何清除?

Swift 泛型函数不起作用

ios - 使用 PageController 快速移动到下一个 ViewMontroller

ios 8 ScrollView 切断内容的宽度

iphone - 使用 UIButton 更改 UIScrollView?