Skip to content
This repository was archived by the owner on Nov 5, 2020. It is now read-only.
This repository was archived by the owner on Nov 5, 2020. It is now read-only.

ContentOffset/ScrollView is jumping when expanding/collapsing cells #22

@gaborcsontos

Description

@gaborcsontos

Hi Guys.

Thanks for this awesome library, it saved my life.
Perhaps I met with an annoying bug.
When I collapsed/expanded a section, the tableview's contentoffset had a weird jumping.
After spent some hours of researching to solve this really annoying problem, I found out the best solution is to set an observer when the contentOffset is changing.

After implementing some properties and the observer, the jumping affect disappears.

fileprivate var isCellUpdateInProgress: Bool = false
fileprivate var lastScrollOffset: CGPoint!
open override var dataSource: UITableViewDataSource? {
	get {
		return super.dataSource
	}
	set(dataSource) {
		guard let dataSource = dataSource else { return }
		expyDataSource = dataSource as? ExpyTableViewDataSource
		super.dataSource = self
        self.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.new, context: nil)
	}
}

private func startAnimating(_ tableView: ExpyTableView, with type: ExpyActionType, forSection section: Int) {

	let headerCell = (self.cellForRow(at: IndexPath(row: 0, section: section)))
	let headerCellConformant = headerCell as? ExpyTableViewHeaderCell
	
    
	CATransaction.begin()

	headerCell?.isUserInteractionEnabled = false
	
	//Inform the delegates here.
	headerCellConformant?.changeState((type == .expand ? .willExpand : .willCollapse), cellReuseStatus: false)
	expyDelegate?.tableView?(tableView, expyState: (type == .expand ? .willExpand : .willCollapse), changeForSection: section)

	CATransaction.setCompletionBlock { [weak self] () -> (Void) in
		//Inform the delegates here.
		headerCellConformant?.changeState((type == .expand ? .didExpand : .didCollapse), cellReuseStatus: false)
		
		self?.expyDelegate?.tableView?(tableView, expyState: (type == .expand ? .didExpand : .didCollapse), changeForSection: section)
		headerCell?.isUserInteractionEnabled = true
        self?.isCellUpdateInProgress = false
	}
    isCellUpdateInProgress = true
    lastScrollOffset = tableView.contentOffset
	tableView.beginUpdates()
    
	//Don't insert or delete anything if section has only 1 cell.
	if let sectionRowCount = expyDataSource?.tableView(tableView, numberOfRowsInSection: section), sectionRowCount > 1 {
		
		var indexesToProcess: [IndexPath] = []
		
		//Start from 1, because 0 is the header cell.
		for row in 1..<sectionRowCount {
			indexesToProcess.append(IndexPath(row: row, section: section))
		}
		//Expand means inserting rows, collapse means deleting rows.
		if type == .expand {
			self.insertRows(at: indexesToProcess, with: expandingAnimation)
		}else if type == .collapse {
			self.deleteRows(at: indexesToProcess, with: collapsingAnimation)
		}
	}
    
    tableView.endUpdates()
    tableView.layer.removeAllAnimations()
    self.setContentOffset(self.lastScrollOffset, animated: false)
	CATransaction.commit()
}

override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "contentOffset" {
        if isCellUpdateInProgress {
            self.setContentOffset(self.lastScrollOffset, animated: false)
        }
    }
}

Hope it will help!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions