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 UIButton prepare/recover and improve .none transition #527

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

p4checo
Copy link
Contributor

@p4checo p4checo commented Nov 19, 2022

Summary

The current RecoverableButtonViewState model only works for very simple buttons where just the title is defined. This means that on more complex scenarios buttons aren't properly "prepared" to enter skeleton mode and remain visible for a while until they are covered with the skeleton layer, where the remaining elements are already in skeleton mode (e.g. labels). Furthermore, when configuring styling on buttons they reorder subviews/sublayers so that the skeleton layer didn't always show on top.

Same thing is true if layer.borderColor is non-nil - the border can be seen for a while until the skeleton layer covers it.

Additionally, using SkeletonTransitionStyle.none would still allow animations to be performed if any change done in
prepareViewForSkeleton triggers a layout pass. This is especially noticeable when pushing a screen in a navigation controller and enabling skeleton mode in viewDidLoad.

Changes

  • Add state, attributedTitle, titleColor, image and backgroundImage to RecoverableButtonViewState, clear them on prepareViewForSkeleton and recover them on recoverViewState (according to state).

  • Set the SkeletonLayer.maskLayer's zPosition to Float.greatestFiniteMagnitude so that it always sits on top of the view's content.

  • Add borderColor to RecoverableViewState, clear it on prepareViewForSkeleton and recover it in recoverViewState.

  • Wrap startTransition block in a UIView.performWithoutAnimation when SkeletonTransitionStyle.none.

  • Remove DispatchQueue.main usage in CALayer animation extensions, as they cause animations to become out of sync with other UI events/animations like navigation pushes and/or other elements that are animated while skeleton is being shown/hidden. Removing them ensures better animation ordering/orchestration.

Demo

skeleton_button_issue_before.mov
skeleton_button_issue_fixed.mov

Requirements

## Motivation

The current `RecoverableButtonViewState` model only works for very
simple buttons where just the title is defined. This means that on more
complex scenarios buttons aren't properly "prepared" to enter skeleton
mode and remain visible for a while until they are covered with the
skeleton layer, where the remaining elements are already in skeleton
mode (e.g. labels). Furthermore, when configuring styling on buttons
they reorder subviews/sublayers so that the skeleton layer didn't
always show on top.

Same thing is true if `layer.borderColor` is non-nil - the border can
be seen for a while until the skeleton layer covers it.

Additionally, using `SkeletonTransitionStyle.none` would still allow
animations to be performed if any change done in
`prepareViewForSkeleton` triggers a layout pass. This is especially
noticeable when pushing a screen in a navigation controller and
enabling skeleton mode in `viewDidLoad`.

## Changes

- Add `state`, `attributedTitle`, `titleColor`, `image` and
`backgroundImage` to `RecoverableButtonViewState`, clear them on
`prepareViewForSkeleton` and recover them on `recoverViewState`
(according to `state`).

- Set the `SkeletonLayer.maskLayer`'s `zPosition` to
`Float.greatestFiniteMagnitude` so that it always sits on top of the
view's content.

- Add `borderColor` to `RecoverableViewState`, clear it on
`prepareViewForSkeleton` and recover it in `recoverViewState`.

- Wrap `startTransition` block in a `UIView.performWithoutAnimation`
when `SkeletonTransitionStyle.none`.

- Fix `DispatchQueue.main` usage in `CALayer` animation extensions.
## Changes

- `DispatchQueue.main.async` calls in `CALAyer` extension cause
animations to become out of sync with other UI events/animations like
navigation pushes and/or other elements that are animated while
skeleton is being shown/hidden. Removing them ensures better animation
ordering/orchestration.
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.

1 participant