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
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ struct RecoverableViewState {
var backgroundColor: UIColor?
var cornerRadius: CGFloat
var clipToBounds: Bool
var borderColor: CGColor?
var isUserInteractionsEnabled: Bool

init(view: UIView) {
self.backgroundColor = view.backgroundColor
self.clipToBounds = view.layer.masksToBounds
self.cornerRadius = view.layer.cornerRadius
self.borderColor = view.layer.borderColor
self.isUserInteractionsEnabled = view.isUserInteractionEnabled
}

Expand Down Expand Up @@ -70,10 +72,20 @@ struct RecoverableImageViewState {
}

struct RecoverableButtonViewState {
var state: UIControl.State
var attributedTitle: NSAttributedString?
var title: String?
var titleColor: UIColor?
var image: UIImage?
var backgroundImage: UIImage?

init(view: UIButton) {
self.title = view.titleLabel?.text
self.state = view.state
self.attributedTitle = view.attributedTitle(for: state)
self.title = view.title(for: state)
self.titleColor = view.titleColor(for: state)
self.image = view.image(for: state)
self.backgroundImage = view.backgroundImage(for: state)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct SkeletonLayer {
self.maskLayer.anchorPoint = .zero
self.maskLayer.bounds = holder.definedMaxBounds
self.maskLayer.cornerRadius = CGFloat(holder.skeletonCornerRadius)
self.maskLayer.zPosition = CGFloat(Float.greatestFiniteMagnitude) // CoreAnimation complains if CGFloat is used
addTextLinesIfNeeded()
self.maskLayer.tint(withColors: colors, traitCollection: holder.traitCollection)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extension UIView {

startTransition { [weak self] in
self?.backgroundColor = .clear
self?.layer.borderColor = nil
}
}

Expand Down Expand Up @@ -101,7 +102,13 @@ extension UIButton {
}

startTransition { [weak self] in
self?.setTitle(nil, for: .normal)
guard let self = self else { return }

self.setTitle(nil, for: self.state)
self.setTitleColor(nil, for: self.state)
self.setAttributedTitle(nil, for: self.state)
self.setImage(nil, for: self.state)
self.setBackgroundImage(nil, for: self.state)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extension UIView: Recoverable {

self.layer.cornerRadius = storedViewState.cornerRadius
self.layer.masksToBounds = storedViewState.clipToBounds
self.layer.borderColor = storedViewState.borderColor

if self.isUserInteractionDisabledWhenSkeletonIsActive {
self.isUserInteractionEnabled = storedViewState.isUserInteractionsEnabled
Expand Down Expand Up @@ -177,8 +178,26 @@ extension UIButton {
override func recoverViewState(forced: Bool) {
super.recoverViewState(forced: forced)
startTransition { [weak self] in
if self?.title(for: .normal) == nil {
self?.setTitle(self?.buttonState?.title, for: .normal)
guard let self = self, let buttonState = self.buttonState else { return }

let state = buttonState.state

if let attributedTitle = buttonState.attributedTitle, self.attributedTitle(for: state) == nil || forced {
self.setAttributedTitle(attributedTitle, for: state)
} else if let title = buttonState.title, self.title(for: state) == nil || forced {
self.setTitle(title, for: state)

if let titleColor = buttonState.titleColor, self.titleColor(for: state) == nil || forced {
self.setTitleColor(titleColor, for: state)
}
}

if let image = buttonState.image, self.image(for: state) == nil || forced {
self.setImage(image, for: state)
}

if let backgroundImage = buttonState.backgroundImage, self.backgroundImage(for: state) == nil || forced {
self.setBackgroundImage(backgroundImage, for: state)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ extension CALayer {
}
}

func playAnimation(_ anim: SkeletonLayerAnimation, key: String, completion: (() -> Void)? = nil) {
func playAnimation(_ anim: @escaping SkeletonLayerAnimation, key: String, completion: (() -> Void)? = nil) {
skeletonSublayers.recursiveSearch(leafBlock: {
DispatchQueue.main.async { CATransaction.begin() }
DispatchQueue.main.async { CATransaction.setCompletionBlock(completion) }
add(anim(self), forKey: key)
DispatchQueue.main.async { CATransaction.commit() }
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
self.add(anim(self), forKey: key)
CATransaction.commit()
}) {
$0.playAnimation(anim, key: key, completion: completion)
}
Expand All @@ -71,22 +71,22 @@ extension CALayer {
}

func setOpacity(from: Int, to: Int, duration: TimeInterval, completion: (() -> Void)?) {
DispatchQueue.main.async { CATransaction.begin() }
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
animation.fromValue = from
animation.toValue = to
animation.duration = duration
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
DispatchQueue.main.async { CATransaction.setCompletionBlock(completion) }
add(animation, forKey: "setOpacityAnimation")
DispatchQueue.main.async { CATransaction.commit() }
self.add(animation, forKey: "setOpacityAnimation")
CATransaction.commit()
}

func insertSkeletonLayer(_ sublayer: SkeletonLayer, atIndex index: UInt32, transition: SkeletonTransitionStyle, completion: (() -> Void)? = nil) {
insertSublayer(sublayer.contentLayer, at: index)
switch transition {
case .none:
DispatchQueue.main.async { completion?() }
completion?()
case .crossDissolve(let duration):
sublayer.contentLayer.setOpacity(from: 0, to: 1, duration: duration, completion: completion)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extension UIView {
func startTransition(transitionBlock: @escaping () -> Void) {
guard let transitionStyle = _currentSkeletonConfig?.transition,
transitionStyle != .none else {
transitionBlock()
UIView.performWithoutAnimation(transitionBlock)
return
}

Expand Down