Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/reload data animation glitch fix #67

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Example/LongListViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,21 @@
import UIKit
import SwiftReorder

private extension String {

/// Generates random string with spaces.
static func random(length: Int, averageWordLength: Int? = nil) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let spacesCount = averageWordLength == nil ? 0 : letters.count / averageWordLength!
let lettersWithSpace = letters.appending(String(repeating: " ", count: spacesCount))
return String((0..<length).map{ _ in lettersWithSpace.randomElement()! })
}
}


class LongListViewController: UITableViewController {

var items = (1...50).map { "Item \($0)" }
var items = (1...10000).map { _ in String.random(length: Int.random(in: 0...200), averageWordLength: 5) }

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
Expand All @@ -41,6 +53,8 @@ class LongListViewController: UITableViewController {
title = "Long List"

tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableView.automaticDimension
tableView.allowsSelection = false
tableView.reorder.delegate = self
}
Expand All @@ -60,6 +74,7 @@ extension LongListViewController {

let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = items[indexPath.row]
cell.textLabel?.numberOfLines = 0

return cell
}
Expand Down
5 changes: 1 addition & 4 deletions Source/ReorderController+DestinationRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ extension ReorderController {

delegate?.tableView(tableView, reorderRowAt: context.destinationRow, to: newContext.destinationRow)

tableView.beginUpdates()
tableView.deleteRows(at: [context.destinationRow], with: .fade)
tableView.insertRows(at: [newContext.destinationRow], with: .fade)
tableView.endUpdates()
tableView.moveRow(at: context.destinationRow, to: newContext.destinationRow)
}

func proposedNewDestinationRow() -> IndexPath? {
Expand Down
1 change: 0 additions & 1 deletion Source/ReorderController+SnapshotView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ extension ReorderController {
guard let tableView = tableView, let superview = tableView.superview else { return }

removeSnapshotView()
tableView.reloadRows(at: [indexPath], with: .none)

guard let cell = tableView.cellForRow(at: indexPath) else { return }
let cellFrame = tableView.convert(cell.frame, to: superview)
Expand Down
27 changes: 21 additions & 6 deletions Source/ReorderController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,14 @@ public class ReorderController: NSObject {

// MARK: - Internal state

struct ReorderContext {
struct ReorderContext: Equatable {
var sourceRow: IndexPath
var destinationRow: IndexPath
var snapshotOffset: CGFloat
var touchPosition: CGPoint
}

enum ReorderState {
enum ReorderState: Equatable {
case ready(snapshotRow: IndexPath?)
case reordering(context: ReorderContext)
}
Expand Down Expand Up @@ -233,14 +233,25 @@ public class ReorderController: NSObject {
let tableTouchPosition = superview.convert(touchPosition, to: tableView)

guard let sourceRow = tableView.indexPathForRow(at: tableTouchPosition),
let sourceCell = tableView.cellForRow(at: sourceRow),
delegate.tableView(tableView, canReorderRowAt: sourceRow)
else { return }

createSnapshotViewForCell(at: sourceRow)
animateSnapshotViewIn()
activateAutoScrollDisplayLink()

tableView.reloadData()
reorderState = .ready(snapshotRow: sourceRow)
tableView.reloadRows(at: [sourceRow], with: .none)

// So after I started to use `reloadRows` instead of `reloadData` I faced with
// strange animation glitches that was caused by too damn smart UITableView
// wasn't removing previous cell while I was dragging during `animateSnapshotViewIn`
// animation. Not easy to reproduce though because need a good timing when you already dragging
// and recognizer decides that it's a good time to begin. Anyway, was able to fix it with removing
// previous cell manually. Ah yes I switched to `reloadRows` to fix cells reordering when there are like
// thousands of cells.
sourceCell.removeFromSuperview()

let snapshotOffset = (snapshotView?.center.y ?? 0) - touchPosition.y

Expand Down Expand Up @@ -312,15 +323,19 @@ public class ReorderController: NSObject {
let cell = UITableViewCell()
let height = snapshotView.bounds.height

NSLayoutConstraint(
item: cell,
let constraint = NSLayoutConstraint(
item: cell.contentView,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 0,
constant: height
).isActive = true
)

// Prevent broken constraints
constraint.priority = .init(999)
constraint.isActive = true

let hideCell: Bool
switch spacerCellStyle {
Expand Down