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

[NT-669, NT-496] Shimmer Loading Extension #980

Merged
merged 9 commits into from
Dec 9, 2019
Merged

Conversation

justinswart
Copy link
Contributor

@justinswart justinswart commented Dec 4, 2019

πŸ“² What

Adds a protocol extension ShimmerLoading for the purpose of adding a shimmering loading state to views.

πŸ€” Why

  • This is a continuation of the UI improvements from our native checkout work.
  • A shimmer loading state hints at the shape of the view that is being loaded rather than just using a native UIActivityIndicatorView.

πŸ›  How

  • Added ShimmerLoading protocol extension.
    • Views that conform to this protocol are extended with startLoading() and stopLoading() functions.
    • All UIViews are given a boolean property shimmersWhenLoading which, when true, means that the shimmering gradient layer is applied to them if their parent conforms to ShimmerLoading and startLoading() is called.
    • Note: I would like to think of a way to do this without extending all UIViews to have that boolean.
  • Created a PledgeShippingLocationShimmerLoadingView example implementation.
    • Technically we could just conform the rootStackView of PledgeShippingLocationViewController to ShimmerLoading and tell it which subviews to apply the shimmer to. While this would work, the shape of the views weren't quite that of the designs so I chose to create a separate view instead.

πŸ‘€ See

Before πŸ› After πŸ¦‹
2019-12-03 16 39 30 2019-12-03 16 36 48

βœ… Acceptance criteria

To have the view appear for longer add this to line 56 of PledgeShippingLocationViewModel:

.ksr_debounce(.seconds(2), on: AppEnvironment.current.scheduler)

We will probably want to make this permanent so that the shimmer is not too brief to be jarring.

  • Navigate to the pledge view of a reward that has shipping. The shimmer loading views should appear in the position of the shipping location section.

@justinswart justinswart changed the title [NT-669] Shimmer Loading Extension [NT-669, NT-496] Shimmer Loading Extension Dec 4, 2019
@@ -117,6 +121,13 @@ final class PledgeShippingLocationViewController: UIViewController {
)
}

self.viewModel.outputs.isLoading
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This output was still dangling but I'll add separate outputs for hiding and showing these.

}

extension UIView {
var shimmersWhenLoading: Bool {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would like to think of a way to not do this to all UIViews.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually a simpler way of doing this is probably just to have the conforming view return an array of views to add the shimmer to. I’ll make that change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree this would be nicer πŸ‘

Copy link
Contributor

Choose a reason for hiding this comment

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

Also the fewer associated objects the better πŸ˜…

override func layoutSubviews() {
super.layoutSubviews()

self.layoutGradientLayers()
Copy link
Contributor

Choose a reason for hiding this comment

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

It's always going to be necessary to call this on the ShimmerLoading-conforming view, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, yeah because we can't override layoutSubviews in an extension πŸ€”

Copy link
Contributor

@ifbarrera ifbarrera left a comment

Choose a reason for hiding this comment

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

Looks good! I think it would be nice not to have to create these sort of shimmer dummy views like PledgeShippingLocationShimmerLoadingView, I wonder if we just set greaterThanOrEqualTo width and height constraints on the views we want the shimmer to appear on if that would be sufficient πŸ€”

}

extension ShimmerLoading where Self: UIView {
private var isLoading: Bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this private isLoading property really needed, or can we just pass it into updateAnimation directly?

func startLoading() {
    self.updateAnimation(isLoading: true)
}

}
}

private func allSubViews(of view: UIView) -> [UIView] {
Copy link
Contributor

Choose a reason for hiding this comment

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

You won't need this if you store var shimmerViews: [UIView] instead right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yip, all gone!

allSubViews(of: self)
.filter { $0.shimmersWhenLoading }
.forEach { view in
let gradientLayer = newGradientLayer(with: view.bounds)
Copy link
Contributor

Choose a reason for hiding this comment

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

Would something like shimmerGradientLayer, shimmerAnimation and shimmerAnimationGroup be clearer naming for these funcs?

}

extension UIView {
var shimmersWhenLoading: Bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also the fewer associated objects the better πŸ˜…

@justinswart
Copy link
Contributor Author

I think it would be nice not to have to create these sort of shimmer dummy views like PledgeShippingLocationShimmerLoadingView, I wonder if we just set greaterThanOrEqualTo width and height constraints on the views we want the shimmer to appear on if that would be sufficient πŸ€”

I'll look into this, it might just mean having to adjust some constraints on the view when it's loading/not loading but yeah that could work!

Copy link
Contributor

@ifbarrera ifbarrera left a comment

Choose a reason for hiding this comment

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

Lgtm! πŸ‘

@justinswart
Copy link
Contributor Author

Going to merge this and look into possibly not using a dummy view separately πŸ‘

@justinswart justinswart merged commit 3f94811 into master Dec 9, 2019
@justinswart justinswart deleted the shimmer-view branch December 9, 2019 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants