Skip to content

Commit

Permalink
Fix skeletons interfering with attributed strings in text-based views (
Browse files Browse the repository at this point in the history
…#520)

When enabling skeleton mode in a text-based view (`UILabel`,
`UITextView`, `UITextField`), it sets the `textColor` to `.clear`,
which is fine when `text` is used, but causes problems when
`attributedText` is used, as it effectively "resets" the string to have
a single color.

Additionally, when a `UILabel` is nested inside a `UIStackView` a
dummy string `" "` was set on the label's `text` so that it didn't have
a 0 height content size. However, this workaround didn't consider the
case where the label already had a non-empty text, meaning that this
(intrusive) `text = " "` broke existing code by clearing the label's
contents.

By improving the corresponding `RecoverableXState` structs, we are able
to preserve each element's contents and state as skeleton is disabled.

Fixes #518.

## Changes

- Create new `RecoverableLabelState` containing a `attributedText` and
`text`, and use it on `UILabel`.

- Update `RecoverableTextViewState` and `RecoverableTextFieldState` to
have a `attributedText`.

- Check if `UILabel`'s `text` is empty before setting dummy value when
enabling skeleton mode in a label nested inside a `UIStackView`.
  • Loading branch information
p4checo authored Oct 20, 2022
1 parent 0058d51 commit 739a4f5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,38 @@ struct RecoverableViewState {

}

struct RecoverableTextViewState {
struct RecoverableLabelState {
var attributedText: NSAttributedString? // we mess with `textColor`, which impacts attributed string if defined
var text: String? // we mess with `text` if the label is within a `UIStackView`
var textColor: UIColor?

init(view: UILabel) {
if let attributedText = view.attributedText {
self.attributedText = attributedText
} else {
self.text = view.text
}
self.textColor = view.textColor
}
}

struct RecoverableTextViewState {
var attributedText: NSAttributedString? // we mess with `textColor`, which impacts attributed string if defined
var textColor: UIColor?

init(view: UITextView) {
self.attributedText = view.attributedText
self.textColor = view.textColor
}
}

struct RecoverableTextFieldState {
var attributedText: NSAttributedString? // we mess with `textColor`, which impacts attributed string if defined
var textColor: UIColor?
var placeholder: String?

init(view: UITextField) {
self.attributedText = view.attributedText
self.textColor = view.textColor
self.placeholder = view.placeholder
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ extension UIView: Recoverable {

extension UILabel {

var labelState: RecoverableTextViewState? {
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableTextViewState }
var labelState: RecoverableLabelState? {
get { return ao_get(pkey: &ViewAssociatedKeys.labelViewState) as? RecoverableLabelState }
set { ao_setOptional(newValue, pkey: &ViewAssociatedKeys.labelViewState) }
}

override func saveViewState() {
super.saveViewState()
labelState = RecoverableTextViewState(view: self)
labelState = RecoverableLabelState(view: self)
}

override func recoverViewState(forced: Bool) {
Expand All @@ -70,6 +70,11 @@ extension UILabel {

if self.textColor == .clear || forced {
self.textColor = storedLabelState.textColor
if let attributedText = storedLabelState.attributedText {
self.attributedText = attributedText
} else {
self.text = storedLabelState.text
}
}
}
}
Expand All @@ -95,6 +100,9 @@ extension UITextView {

if self?.textColor == .clear || forced {
self?.textColor = storedLabelState.textColor
if let attributedText = storedLabelState.attributedText {
self?.attributedText = attributedText
}
}
}
}
Expand All @@ -120,6 +128,9 @@ extension UITextField {

if self?.textColor == .clear || forced {
self?.textColor = storedLabelState.textColor
if let attributedText = storedLabelState.attributedText {
self?.attributedText = attributedText
}
}

if self?.placeholder == nil || forced {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension UILabel {
guard estimatedNumberOfLines > 1 || estimatedNumberOfLines == 0 else { return }

// Workaround to simulate content when the label is contained in a `UIStackView`.
if isSuperviewAStackView, bounds.height == 0 {
if isSuperviewAStackView, bounds.height == 0, (text?.isEmpty ?? true) {
// This is a placeholder text to simulate content because it's contained in a stack view in order to prevent that the content size will be zero.
text = " "
}
Expand Down

0 comments on commit 739a4f5

Please sign in to comment.