前言
我在iOS 10上有一个有效的自定义const recur = (...values) =>
({ type: recur, values })
const loop = f =>
{
let acc = f ()
while (acc && acc.type === recur)
acc = f (...acc.values)
return acc
}
const explore = $node =>
loop (([x,...xs] = [$node], k = x => x) => {
if (x === undefined)
return k ()
else {
x.visited = true
preVisit (x)
return recur (
Array.from (x.adjacencies)
.filter (n => n.visited === false)
.concat (xs),
() => (postVisit (x), k ())
)
}
})
// for completion's sake
let visitCounter = 0
const preVisit = node =>
node.preVisit = visitCounter++
const postVisit = node =>
node.postVisit = visitCounter++
解雇动画。它的实现方式如下:
UITableViewCell
的子视图的索引零处创建,定位和插入(在单元格的UITableViewCell
下方)contentView
动画显示为帧外动画
contentView
完全超出框架时,会调用原生contentView
方法UITableView
。 deleteRows(at: [indexPath], with: .top)
折叠,自定义视图在前一个UITableViewCell
折叠后被屏蔽。下面是它的慢动画:
注意:UITableViewCell
具有清晰的背景色,允许在其后面显示自定义视图(蓝色)。每个单元格都有tableView
,其中包含单元格的所有内容。 containerView
和containerView
都有明确的背景颜色。一切都很好,花花公子。
问题
将我的应用迁移到iOS 11,此动画无法正常运行。下面是一个慢动画,它不再有效了。
正如您所看到的,自定义视图在单元格解除后覆盖在上一个单元格的上,而不会更改我的代码。
到目前为止的调查
到目前为止,我已经确定contentView
的解剖结构已经改变了:
UITableView
对此:( UITableView
UITableViewWrapperView
cell
custom view
contentView
cell separator view
cell
cell
cell
UIView
UIImageView (scroll view indicator bottom)
UIImageView (scroll view indicator right)
已被删除)
UITableViewWrapperView
我注意到有关此UITableView
cell
custom view
contentView
cell separator view
cell
cell
cell
UIView
UIImageView (scroll view indicator bottom)
UIImageView (scroll view indicator right)
的一件事是它的图层的UITableWrapperView
属性为true,而isOpaque
属性为false masksToBounds
和所有UITableView
相反。由于此视图在iOS 11中被删除,这可能会导致我出现错误效果的原因。我真的不知道。
编辑:我发现的另一件事是工作示例中的UITableViewCell
在其子视图的零索引处插入了一个神秘的UITableWrapperView
(所有UIView
} s)哪些属性UITableViewCell
设置为true并且它具有isOpaque
。随后在动画完成后删除此视图。由于在iOS 11中删除了compositingFilter
,因此该视图通过关联也会丢失。
问题
首先,是否有人知道为什么这种行为发生了变化?如果没有,是否有另一种方法可以更好地实现iOS 10中的效果?我希望清楚UITableWrapperView
s但是有一个自定义视图,在解雇时显示在每个单元格后面,当被解除时被其他清除UITableViewCell
屏蔽,如上面第一个gif示例所示。
答案 0 :(得分:1)
在删除行之前,请将要删除的单元格发送到表格视图子视图的背面。
tableView.sendSubview(toBack: cell)
tableView.deleteRows(at: [indexPath], with: .top)
如果您没有单元格,可以使用索引路径检索它。
guard let cell = tableView.cell(for: indexPath) else { return }
// ...
这应该适用于视图层次结构的调整。
<强> CardTableViewController.swift 强>
class CardTableViewController: UITableViewController, CardTableViewCellDelegate {
// MARK: Outlets
@IBOutlet var segmentedControl: UISegmentedControl!
// MARK: Properties
private var cards: [Card] = [
Card(text: "Etiam porta sem malesuada magna mollis euismod. Maecenas faucibus mollis interdum."),
Card(text: "Nulla vitae elit libero, a pharetra augue. Cras justo odio, dapibus ac facilisis in, egestas eget quam."),
Card(text: "Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis.")
]
var selectedIndex: Int { return segmentedControl.selectedSegmentIndex }
var tableCards: [Card] {
return cards.filter { selectedIndex == 0 ? !$0.isDone : $0.isDone }
}
// MARK: UITableViewDataSource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableCards.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CardTableViewCell
cell.card = tableCards[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
// MARK: CardTableViewCellDelegate
func cardTableViewCell(_ cell: CardTableViewCell, didTouchUpInsideCheckmarkButton button: UIButton) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
cell.card?.isDone = button.isSelected
cell.card?.dayCount += button.isSelected ? 1 : -1
cell.customView?.dayCount = cell.card?.dayCount
UIView.animate(withDuration: 0.7, delay: 0.3, options: .curveEaseIn, animations: {
cell.checkmarkButton?.superview?.transform = .init(translationX: cell.frame.width, y: 0)
cell.customView?.alpha = 1
}) { _ in
self.tableView.sendSubview(toBack: cell)
self.tableView.deleteRows(at: [indexPath], with: .top)
}
}
// MARK: Actions
@IBAction func didChangeSegmentedControl(_ sender: UISegmentedControl) {
tableView.reloadData()
}
}
<强> CardTableViewCell.swift 强>
@objc protocol CardTableViewCellDelegate {
func cardTableViewCell(_ cell: CardTableViewCell, didTouchUpInsideCheckmarkButton button: UIButton)
}
@IBDesignable class CardTableViewCell: UITableViewCell {
// MARK: Outlets
@IBOutlet var checkmarkButton: UIButton?
@IBOutlet var customView: CardCustomView?
@IBOutlet var delegate: CardTableViewCellDelegate?
@IBOutlet var taskTextLabel: UILabel?
// MARK: Properties
var card: Card? {
didSet {
updateOutlets()
}
}
// MARK: Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
checkmarkButton?.layer.borderColor = UIColor.black.cgColor
}
override func prepareForReuse() {
super.prepareForReuse()
card = nil
}
// MARK: Methods
private func updateOutlets() {
checkmarkButton?.isSelected = card?.isDone == true ? true : false
checkmarkButton?.superview?.transform = .identity
customView?.alpha = 0
customView?.dayCount = card?.dayCount
taskTextLabel?.text = card?.text
}
// MARK: Actions
@IBAction func didTouchUpInsideCheckButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
delegate?.cardTableViewCell(self, didTouchUpInsideCheckmarkButton: sender)
}
}
class CardCustomView: UIView {
// MARK: Outlets
@IBOutlet var countLabel: UILabel?
@IBOutlet var daysLabel: UILabel?
// MARK: Properties
var dayCount: Int? {
didSet {
updateOutlets()
}
}
override func awakeFromNib() {
super.awakeFromNib()
updateOutlets()
}
// MARK: Methods
private func updateOutlets() {
let count = dayCount.flatMap { $0 } ?? 0
countLabel?.text = "\(dayCount.flatMap { $0 } ?? 0)"
daysLabel?.text = "Day\(count == 1 ? "" : "s") in a row"
}
}
<强> Card.swift 强>
class Card: NSObject {
// MARK: Properties
var dayCount: Int = 0
var isDone: Bool = false
var text: String
// MARK: Lifecycle
init(text: String) {
self.text = text
}
}
答案 1 :(得分:1)
首先,我不认为缺少UITableViewWrapperView
是个问题。
这是父视图,父母不能掩盖儿童观点。
请注意,问题是哪个单元格遮挡了哪个。在第一种情况下,行A遮挡了行B,而在第二行B遮蔽了行A(在这种情况下,您的自定义B单元格具有透明背景)。
看起来苹果已经搞砸了细胞之间的关系。为了解决这个问题,我会尝试修复这种关系。所以在动画的第二部分开始之前我会尝试:
cell.superview.sendSubview(toBack: cell)
这不应该破坏任何东西(在较旧的iOS版本上)并且应该解决iOS 11的问题。
答案 2 :(得分:1)
我花了很多天学习但却失败了。
<强> iOS10 强>
在deleteRows
之后,TableViewCell
的视图中包含compositingFilter
属性,其值为copy
,视图隐藏了此背后的所有视图。
我们可以尝试删除TableViewCell
时生成的deleteRows
子视图。然后iOS 10的行为就像iOS11。
然后我们可以尝试再次将视图(UIView()
)添加到TableViewCell
并将compositingFilter
设置为copy
(字符串),它将重新实现in iOS10
试。
但iOS11中的任何操作失败。它将在iOS11中产生黑色背景。
我相信在iOS11上更改了图层的行为。
当up
的背景透明时,我们不得不考虑暂时放弃使用ios11
中的TableViewCell
动画。
答案 3 :(得分:1)
在iOS 11上查看应用程序后我遇到了这样的问题,问题是从表格视图中删除行时的动画:
很明显,折叠动画是不合适的,因为要删除多行。
以下是扩展/折叠行的负责代码:
// inserting rows:
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
tableView.endUpdates()
// deleting rows:
tableView.beginUpdates()
tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .automatic)
tableView.endUpdates()
显然,还有编辑数据源数组的代码。
导致此问题的原因是 - 只是 - 已分配的UITableViewRowAnimation到automatic;我所做的只是将动画更改为fade
:
// inserting rows:
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
tableView.endUpdates()
// deleting rows:
tableView.beginUpdates()
tableView.deleteRows(at: [IndexPath(row: 4 + count, section: 0), IndexPath(row: 5 + count, section: 0), IndexPath(row: 6 + count, section: 0)], with: .fade)
tableView.endUpdates()
输出已修复为:
同时强>
您可能需要查看可能与您的问题相关的以下问题:
答案 4 :(得分:0)
UITableView
具有固定大小的单元格在这种方法中,我决定在UITableViewCell
的内容视图中添加补充视图,并将其高度约束设置为0
以及行删除动画。
为了简单起见,我只介绍此解决方案的要点。
deleteRows(at:with:)
方法。0
。我不会在这里描述整个自动布局设置,因为它会模糊解决方案的主要思想。所有构建块都相当简单,但有一些。您可以在此GitHub repository中找到完整的工作项目。
不幸的是,由于动画定时,这种解决方案对动态高度单元的效果不佳。我不确定它会解决您的问题,因为据我所知,您正在使用动态高度单元格。 但是,我希望它会推动你朝着正确的方向前进,或者帮助有类似问题的人。