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

Adds a scroll offset manager class which caches and restores scroll offsets #63

Merged
merged 7 commits into from Sep 3, 2020

Conversation

simonmitchell
Copy link
Contributor

Description

Adds ScrollOffsetManager for storing and restoring scroll offsets via a protocol implementation.

This ensures that scroll offsets are only remembered where users explicitly
request them to be, meaning we won't interfere with any custom logic they
already have to handle this.

Also adds examples of this to the demo project

Related Issue

N/A

Motivation and Context

Bugs were found in Blood within ThunderCloud where scroll offsets were incorrect due to cell re-use. This allows us to handle this better by caching scroll offsets where required.

How Has This Been Tested?

Has been tested using the demo project, and will shortly be tested within ThunderCloud and specifically in the case of Blood

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

…lows

for restoring scroll offsets via a protocol implementation.
This ensures that scroll offsets are only remembered where users explicitly
request them to be, meaning we won't interfere with any custom logic they
already have to handle this.

Also adds examples of this to the demo project
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false

scrollable.scrollView?.setContentOffset(newOffset, animated: animated)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrollView was unwrapped above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! 🤦

//MARK: Scroll Offset Management
//MARK:

private lazy var scrollOffsetManager: ScrollOffsetManager = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you here, there's nothing wrong with doing it with = { }() in case you add properties in the future. But atm could simply do private let scrollOffsetManager = ScrollOffsetManager()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let's go with that. It's memory footprint should be tiny anyways!

}
}

func updateScrollPosition(cell: UITableViewCell, at indexPath: IndexPath) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No harm in an animated parameter? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done... and documented!


return TableSection(
rows: [
CollectionRow(colours: [.red, .green, .blue, .brown, .cyan, .darkGray, .darkText]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issue, could use

(0 ..< 18).map { _ in 
    CollectionRow(colours: [.red, .green, .blue, .brown, .cyan, .darkGray, .darkText])
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do that! :D

var scrollDelegate: ScrollOffsetDelegate? { get set }

/// An identifier used by `ScrollOffsetManager`
var identifier: AnyHashable? { get set }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can defo see why if the implementor providing an identifier is real nice. Hence this. But it's a little annoying to have to provide it. Maybe I'm overlooking here, how's this going to work if some provide it and some don't?

Anyway we probably want some default implementations here? :) Like this and delegate as nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So TableViewController actually sets this to the given IndexPath so all implementers have to do is provide the property. Not sure if that makes sense to you? It just means all information is stored on the cell itself, and we don't need to fetch different bits of info from different places. Maybe I need to make that clearer in the docs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well Apple choose not to put an IndexPath property on the UITableViewCell. That's where the manager would hold onto that mapping. I'll come back to

Copy link
Contributor

@BenShutt BenShutt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great PR :) Nice one Si! 😄

Approving. My only other comment would be:
Do we need the identifier on the ScrollOffsetManagable. Apple actively choose not to have an indexPath property on the TableViewCell.

So wondering if the ScrollOffsetManager should map IndexPaths to offsets, which we invalidate when the data changes (like you've done, but simplified)

Anyway, as I say, nice work!

@simonmitchell
Copy link
Contributor Author

That's a great shout @BenCShutt happy to revisit! Want to keep it as-is for now, as storing the identifier on the ScrollOffsetManagable means we can re-access the key from that protocol in order to store it in the cache map :D Other option would possibly be to store the ScrollOffsetManagable alongside the key to re-find said key, but then we are keeping a strong reference to ScrollOffsetManagable which are normally UITableViewCell :/

@simonmitchell simonmitchell merged commit 081ed72 into develop Sep 3, 2020
@BenShutt BenShutt deleted the feature/scroll_offset_memory branch August 25, 2022 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants