我有一个简单的项目,其故事板只包含一个UICollectionViewController
,使用Xcode 7.1.1 for iOS 9.1构建
class ViewController: UICollectionViewController {
var values = ["tortile", "jetty", "tisane", "glaucia", "formic", "agile", "eider", "rooter", "nowhence", "hydrus", "outdo", "godsend", "tinkler", "lipscomb", "hamlet", "unbreeched", "fischer", "beastings", "bravely", "bosky", "ridgefield", "sunfast", "karol", "loudmouth", "liam", "zunyite", "kneepad", "ashburn", "lowness", "wencher", "bedwards", "guaira", "afeared", "hermon", "dormered", "uhde", "rusher", "allyou", "potluck", "campshed", "reeda", "bayonne", "preclose", "luncheon", "untombed", "northern", "gjukung", "bratticed", "zeugma", "raker"]
@IBOutlet weak var flowLayout: UICollectionViewFlowLayout!
override func viewDidLoad() {
super.viewDidLoad()
flowLayout.estimatedItemSize = CGSize(width: 10, height: 10)
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return values.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! MyCell
cell.name = values[indexPath.row]
return cell
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
values.removeAtIndex(indexPath.row)
collectionView.deleteItemsAtIndexPaths([indexPath])
}
}
class MyCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
var name: String? {
didSet {
label.text = name
}
}
}
从集合视图中删除单元格时,所有剩余的单元格将显示为estimatedItemSize
的动画,然后交换回正确的大小。
有趣的是,这会在动画发生时为每个单元格生成自动布局约束警告:
2015-12-02 14:30:45.236 CollectionTest[1631:427853] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x14556f780 h=--& v=--& H:[UIView:0x1456ac6c0(10)]>",
"<NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830'raker'.trailing>",
"<NSLayoutConstraint:0x1456ad020 UILabel:0x1456ac830'raker'.leading == UIView:0x1456ac6c0.leadingMargin>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x1456acfd0 UIView:0x1456ac6c0.trailingMargin == UILabel:0x1456ac830'raker'.trailing>
我最初的想法是,打破这些限制是导致调整大小问题的原因。
更新单元格的awakeFromNib
方法:
override func awakeFromNib() {
super.awakeFromNib()
contentView.translatesAutoresizingMaskIntoConstraints = false
}
修复警告,但问题仍然存在。
我尝试在单元格及其contentView
之间重新添加自己的约束,但这并没有解决问题:
override func awakeFromNib() {
super.awakeFromNib()
contentView.translatesAutoresizingMaskIntoConstraints = false
for constraint in [
contentView.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
contentView.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
contentView.topAnchor.constraintEqualToAnchor(topAnchor),
contentView.bottomAnchor.constraintEqualToAnchor(bottomAnchor)]
{
constraint.priority = 999
constraint.active = true
}
}
思想?
答案 0 :(得分:2)
流布局在按布局估算尺寸后计算单元格的实际尺寸,以定义哪些是可见的。之后,它会根据实际尺寸调整布局。
然而,当它动画时,当它计算动画的初始位置时,它不会到达出列单元格并在那里运行自动布局的阶段,所以它只使用估计的大小。
最简单的方法是尝试提供最接近的估算尺寸,或者如果您可以在sizeForItemAt
来电中提供代表的尺寸。
在我的情况下,我试图在不插入或删除单元格的情况下为layoutAttributes设置动画,对于特定情况,我将UICollectionViewFlowLayout
子类化,然后重写此方法:
override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) {
if !context.invalidateEverything && context.invalidatedItemIndexPaths == nil && context.contentOffsetAdjustment == .zero && context.contentSizeAdjustment == .zero {
return
}
super.invalidateLayout(with: context)
}
这可以防止在没有任何更改时使用估计的大小重新计算布局属性。
答案 1 :(得分:1)
TL; DR:我只能获得一个集合视图,以使其与委托sizeForItem方法一起正常运行。这里的工作示例:https://github.com/chrisco314/CollectionView-AutoLayout
在控制器中:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
var cell = Cell.prototype
let contents = data[indexPath.section][indexPath.item]
cell.text = contents
cell.expand = selected.contains(indexPath)
let width = collectionView.bounds
.inset(collectionView.contentInset)
.inset(layout.sectionInset)
.width
let finalSize = cell.systemLayoutSizeFitting(
.init(width: width, height: 0),
withHorizontalFittingPriority: .required,
verticalFittingPriority: .fittingSizeLevel)
.withWidth(width)
print("sizeForItemAt: \(finalSize)")
return finalSize
}
在单元格中:
override func systemLayoutSizeFitting(
_ targetSize: CGSize,
withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority,
verticalFittingPriority: UILayoutPriority) -> CGSize {
let contentSize = contentView.systemLayoutSizeFitting(
targetSize,
withHorizontalFittingPriority: horizontalFittingPriority,
verticalFittingPriority: verticalFittingPriority)
return contentSize
}
展开面板的约束:
lazy var panel: UIView = {
let view = Panel()
view.pin(body, to: .left, .top, .right)
view.clipsToBounds = true
panelHeight = view.heightAnchor.constraint(equalTo: body.heightAnchor)
return view
}()
var panelHeight: NSLayoutConstraint!
lazy var height:CGFloat = 60
lazy var body: UIView = {
let view = Body()
view.backgroundColor = .blue
view.pin(contents, inset: 9)
let bodyHeight = view.heightAnchor.constraint(equalToConstant: height)
bodyHeight.isActive = true
return view
}()
lazy var contents: UILabel = {
let label = UILabel()
label.backgroundColor = .white
label.numberOfLines = 0
label.text = "Body with height constraint of \(height)"
return label
}()
我遇到了很多类似的问题,并且花了很多愚蠢的时间来尝试找到一条适用于所有情况的路径-使用自动布局渲染,用于插入和删除的合理动画,处理旋转等。以我的经验,唯一有效的方法是使用sizeForItem委托方法。您可以使用estimateSize和自动布局,但对我而言,动画将始终折叠到顶部,然后所有内容再次下降-也许您正在查看。
我有一个样品,基本上是我进行测试的场所。我在这里使用选项卡视图控制器的不同选项卡尝试了不同的方法,使用估计的大小,单元格自身的约束,返回所需大小的自定义systemSizeFitting以及基于委托的sizeThatFits
该示例有些复杂,但是第三个选项卡演示了基于委托的方法,该方法可用于扩展单元格以及插入和删除动画。注意tab2吗?根据扩展单元的比例演示集合视图使用的不一致动画。如果该比例大于2:1,则它会褪色并捕捉;如果该比例小于2:1,则它会平滑地上下动画。
所有涉及动画的非委托方法都失败了,如上所述。也许有一种方法可以不使用委托方法(我很想看看是否可行),但是我找不到它。