我正在使用Swift在iOS 8.4中构建应用程序。
我有UITableView
个自定义UITableViewCell
,其中包含UILabel
和UIImageView
。这一切都很直接,一切都很好。
我试图创建一个类似于demonstrated in this demo的视差效果。
我目前在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
收听课堂上的滚动事件。
除此之外,感谢帮助!
答案 0 :(得分:27)
我明白了!我们的想法是在没有实现任何额外库的情况下执行此操作,特别是考虑到实现的简单性。
首先......在自定义表视图Cell
类中,您必须创建一个包装器视图。您可以在原型单元格中选择UIImageView
,然后选择Editor > Embed in > View
。将两个拖动到您的单元格作为出口,然后为包含视图设置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
的{{1}}属性。见下文:
.frame
答案 1 :(得分:25)
我对@ded的解决方案不太满意,需要一个包装器视图,所以我想出了另一个使用autolayout的解决方案,并且非常简单。
在故事板中,您只需添加imageView并在ImageView上设置4个约束:
最后两个约束(顶部和高度)需要引用自定义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)
}
}
}
注意:
所以你有它,parallax UITableViewCells应该适用于任何布局,也可以适应CollectionViews。
答案 2 :(得分:2)
此方法适用于表格视图和集合视图。
首先为tableview创建单元格并将图像视图放入其中。
将图像高度设置为略高于单元格高度。如果单元格高度= 160,则让图像高度为200(以产生视差效果,您可以相应地更改它)
将这两个变量放在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更改为collectionView变量
就是这样。我不确定这是不是最好的方法。但它对我有用。希望它也适合你。并告诉我是否有任何问题
答案 3 :(得分:0)
结合@ded和@Nycen的答案后,我来到了此解决方案,该解决方案使用嵌入式视图,但更改了布局约束(仅其中之一):
在Interface Builder中,将图像视图嵌入到UIView中。对于该视图,请在视图>绘图中选中[√] Clips to bounds
从图像中添加以下约束以进行查看:左右,垂直居中,高度
调整高度限制,以使图像略高于视图
对于Align Center Y约束,在您的UITableViewCell中插入一个插座
将此功能添加到视图控制器(可以是UITableViewController或UITableViewControllerDelegate)
private static let screenMid = UIScreen.main.bounds.height / 2
private func adjustParallax(for cell: MyTableCell) {
cell.imageCenterYConstraint.constant = -(cell.frame.origin.y - MyViewController.screenMid - self.tableView.contentOffset.y) / 10
}
注意:通过编辑幻数10
,您可以更改效果的应用程度,并从等式中删除-
符号,可以更改效果的方向
从重用单元格开始调用函数:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCellId", for: indexPath) as! MyTableCell
adjustParallax(for: cell)
return cell
}
以及发生滚动时:
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
(self.tableView.visibleCells as! [MyTableCell]).forEach { cell in
adjustParallax(for: cell)
}
}