如何使用UIImageView在其原型单元格中创buildUITableView中的视差效果

我正在用Swift在iOS 8.4中构build一个应用程序。

我有一个UITableView与自定义的UITableViewCell ,包括UILabelUIImageView 。 这是相当直接的,一切都很好。

我试图创build一个类似于这个演示中演示的视差效果。

我目前有这个代码在我的tableView.cellForRowAtIndexPath

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = self.tableView.dequeueReusableCellWithIdentifier("myitem", forIndexPath: indexPath) as! MixTableViewCell cell.img.backgroundColor = UIColor.blackColor() cell.title.text = self.items[indexPath.row]["title"] cell.img.image = UIImage(named: "Example.png") // ideally it would be cool to have an extension allowing the following // cell.img.addParallax(50) // or some other configurable offset return cell } 

该块存在于类似class HomeController: UIViewController, UITableViewDelegate, UITableViewDataSource { ... }

我也知道,我可以通过func scrollViewDidScroll我的课程中的滚动事件。

除此之外,帮助表示赞赏!

我想到了! 这个想法是在没有实现任何额外的库的情况下做的,特别是考虑到实现的简单性。

首先…在自定义表格视图Cell类中,您必须创build一个包装视图。 您可以在Prototype单元格中select您的UIImageView ,然后select“ Editor > Embed in > ViewclipToBounds = true两个拖放到您的Cell中,然后为包含的视图设置clipToBounds = true 。 (还请记住将约束设置为与图像相同。

 class MyCustomCell: UITableViewCell { @IBOutlet weak var img: UIImageView! @IBOutlet weak var imgWrapper: UIView! override func awakeFromNib() { self.imgWrapper.clipsToBounds = true } } 

然后在你的UITableViewController子类(或委托),实现scrollViewDidScroll – 从这里你将不断更新UIImageView.frame属性。 见下文:

 override func scrollViewDidScroll(scrollView: UIScrollView) { let offsetY = self.tableView.contentOffset.y for cell in self.tableView.visibleCells as! [MyCustomCell] { let x = cell.img.frame.origin.x let w = cell.img.bounds.width let h = cell.img.bounds.height let y = ((offsetY - cell.frame.origin.y) / h) * 25 cell.img.frame = CGRectMake(x, y, w, h) } } 

看到这在行动 。

我不太满意@ ded的解决scheme需要一个包装视图,所以我想出了另一个使用自动布局,很简单。

在故事板中,您只需添加imageView并在ImageView上设置4个约束:

  • 通向ContentView(即Superview)= 0
  • 跟踪到ContentView(即Superview)= 0
  • 顶部空间到ContentView(即Superview)= 0
  • ImageView Height(在这里设置为200,但是这是根据单元格高度重新计算的)

在这里输入图像说明

最后两个约束(顶部和高度)需要引用出口到您的自定义UITableViewCell(在上图中,双击最右边列中的约束,然后显示连接检查器 – 图标是一个圆圈中的箭头)

你的UITableViewCell应该是这样的:

 class ParallaxTableViewCell: UITableViewCell { @IBOutlet weak var parallaxImageView: UIImageView! // MARK: ParallaxCell @IBOutlet weak var parallaxHeightConstraint: NSLayoutConstraint! @IBOutlet weak var parallaxTopConstraint: NSLayoutConstraint! override func awakeFromNib() { super.awakeFromNib() clipsToBounds = true parallaxImageView.contentMode = .ScaleAspectFill parallaxImageView.clipsToBounds = false } } 

所以基本上,我们告诉图像占用尽可能多的空间,但我们将其剪切到单元框架。

现在你的TableViewController应该看起来像这样:

 class ParallaxTableViewController: UITableViewController { override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return cellHeight } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath) as! ParallaxTableViewCell cell.parallaxImageView.image = … // Set your image cell.parallaxHeightConstraint.constant = parallaxImageHeight cell.parallaxTopConstraint.constant = parallaxOffsetFor(tableView.contentOffset.y, cell: cell) return cell } // Change the ratio or enter a fixed value, whatever you need var cellHeight: CGFloat { return tableView.frame.width * 9 / 16 } // Just an alias to make the code easier to read var imageVisibleHeight: CGFloat { return cellHeight } // Change this value to whatever you like (it sets how "fast" the image moves when you scroll) let parallaxOffsetSpeed: CGFloat = 25 // This just makes sure that whatever the design is, there's enough image to be displayed, I let it up to you to figure out the details, but it's not a magic formula don't worry :) var parallaxImageHeight: CGFloat { let maxOffset = (sqrt(pow(cellHeight, 2) + 4 * parallaxOffsetSpeed * tableView.frame.height) - cellHeight) / 2 return imageVisibleHeight + maxOffset } // Used when the table dequeues a cell, or when it scrolls func parallaxOffsetFor(newOffsetY: CGFloat, cell: UITableViewCell) -> CGFloat { return ((newOffsetY - cell.frame.origin.y) / parallaxImageHeight) * parallaxOffsetSpeed } override func scrollViewDidScroll(scrollView: UIScrollView) { let offsetY = tableView.contentOffset.y for cell in tableView.visibleCells as! [MyCustomTableViewCell] { cell.parallaxTopConstraint.constant = parallaxOffsetFor(offsetY, cell: cell) } } } 

笔记:

  • 使用tableView.dequeueReusableCellWithIdentifier(“CellIdentifier”,forIndexPath:indexPath)而不是tableView.dequeueReusableCellWithIdentifier(“CellIdentifier”)非常重要,否则在开始滚动之前图像不会被偏移

所以你有它,视差UITableViewCells应该适用于任何布局,也可以适应CollectionViews。

此方法适用于表视图和集合视图。

  • 首先为tableview创build单元格,并将图像视图放在其中。

  • 将图像高度设置为比单元格高度略高。 如果单元格高度= 160,则图像高度为200(为了产生视差效果,并且可以相应地改变它)

  • 把这两个variables放在你的viewController或者你的tableView委托被扩展的任何类中

 let imageHeight:CGFloat = 150.0 let OffsetSpeed: CGFloat = 25.0 
  • 在同一个类中添加下面的代码
  func scrollViewDidScroll(scrollView: UIScrollView) { // print("inside scroll") if let visibleCells = seriesTabelView.visibleCells as? [SeriesTableViewCell] { for parallaxCell in visibleCells { var yOffset = ((seriesTabelView.contentOffset.y - parallaxCell.frame.origin.y) / imageHeight) * OffsetSpeedTwo parallaxCell.offset(CGPointMake(0.0, yOffset)) } } } 
  • seriesTabelView是我的UItableView

  • 现在让我们转到这个tableView的单元格,并添加下面的代码

 func offset(offset: CGPoint) { posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y) } 
  • 是posterImage是我的UIImageView

如果你想实现这个collectionView只是改变tableView vairable到你的collectionViewvariables

这就是它。 我不确定这是否是最好的方法。 但它适用于我。 希望它也适合你。 并让我知道是否有任何问题