fix: StatefulButton appearance configuration
This commit is contained in:
parent
094c0c40d8
commit
1a4c42fa46
|
|
@ -24,65 +24,21 @@ import TIUIKitCore
|
|||
import UIKit
|
||||
|
||||
extension UIButton {
|
||||
public func configureUIButton(appearance: BaseAppearance<some ViewLayout, some BaseContentLayout>) {
|
||||
public func configureUIButton(appearance: BaseAppearance<some ViewLayout, some BaseContentLayout>,
|
||||
for state: UIControl.State = .normal) {
|
||||
|
||||
appearance.textAttributes?
|
||||
.configure(button: self,
|
||||
with: titleLabel?.attributedText?.string ?? titleLabel?.text)
|
||||
with: title(for: state),
|
||||
for: state)
|
||||
|
||||
if #available(iOS 15, *) {
|
||||
var config = configuration ?? .plain()
|
||||
|
||||
let contentInsets = appearance.contentLayout.contentInsets
|
||||
let titleInsets = appearance.contentLayout.titleInsets
|
||||
let imageInsets = appearance.contentLayout.imageInsets
|
||||
|
||||
let topContentInset = contentInsets.top + titleInsets.top
|
||||
let bottomContentInset = contentInsets.bottom + titleInsets.bottom
|
||||
|
||||
let fullLeadingContentInset = contentInsets.left + titleInsets.left
|
||||
let fullTrailingContentInset = contentInsets.right + titleInsets.right
|
||||
|
||||
let hasNonEmptyImage = [
|
||||
config.image,
|
||||
currentImage
|
||||
]
|
||||
.compactMap { $0 }
|
||||
.first { !($0.size.width.isZero || $0.size.height.isZero) } != nil
|
||||
|
||||
if hasNonEmptyImage {
|
||||
let leadingContentInset: CGFloat
|
||||
let trailingContentInset: CGFloat
|
||||
let imagePadding: CGFloat
|
||||
|
||||
switch config.imagePlacement {
|
||||
case .leading:
|
||||
leadingContentInset = contentInsets.left
|
||||
trailingContentInset = fullTrailingContentInset
|
||||
imagePadding = titleInsets.left + imageInsets.right
|
||||
|
||||
case .trailing:
|
||||
leadingContentInset = fullLeadingContentInset
|
||||
trailingContentInset = contentInsets.right
|
||||
imagePadding = titleInsets.right + imageInsets.left
|
||||
|
||||
default:
|
||||
leadingContentInset = fullLeadingContentInset
|
||||
trailingContentInset = fullTrailingContentInset
|
||||
imagePadding = .zero
|
||||
}
|
||||
|
||||
config.contentInsets = NSDirectionalEdgeInsets(top: topContentInset,
|
||||
leading: leadingContentInset,
|
||||
bottom: bottomContentInset,
|
||||
trailing: trailingContentInset)
|
||||
|
||||
config.imagePadding = imagePadding
|
||||
} else {
|
||||
config.contentInsets = NSDirectionalEdgeInsets(top: topContentInset,
|
||||
leading: fullLeadingContentInset,
|
||||
bottom: bottomContentInset,
|
||||
trailing: fullTrailingContentInset)
|
||||
}
|
||||
configureInsets(in: &config,
|
||||
contentInsets: appearance.contentLayout.contentInsets,
|
||||
titleInsets: appearance.contentLayout.titleInsets,
|
||||
imageInsets: appearance.contentLayout.imageInsets)
|
||||
|
||||
configuration = config
|
||||
} else {
|
||||
|
|
@ -93,4 +49,59 @@ extension UIButton {
|
|||
|
||||
super.configureUIView(appearance: appearance)
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
private func configureInsets(in config: inout UIButton.Configuration,
|
||||
contentInsets: UIEdgeInsets,
|
||||
titleInsets: UIEdgeInsets,
|
||||
imageInsets: UIEdgeInsets) {
|
||||
|
||||
let topContentInset = contentInsets.top + titleInsets.top
|
||||
let bottomContentInset = contentInsets.bottom + titleInsets.bottom
|
||||
|
||||
let fullLeadingContentInset = contentInsets.left + titleInsets.left
|
||||
let fullTrailingContentInset = contentInsets.right + titleInsets.right
|
||||
|
||||
let hasNonEmptyImage = [
|
||||
config.image,
|
||||
currentImage
|
||||
]
|
||||
.compactMap { $0 }
|
||||
.first { !($0.size.width.isZero || $0.size.height.isZero) } != nil
|
||||
|
||||
if hasNonEmptyImage {
|
||||
let leadingContentInset: CGFloat
|
||||
let trailingContentInset: CGFloat
|
||||
let imagePadding: CGFloat
|
||||
|
||||
switch config.imagePlacement {
|
||||
case .leading:
|
||||
leadingContentInset = contentInsets.left
|
||||
trailingContentInset = fullTrailingContentInset
|
||||
imagePadding = titleInsets.left + imageInsets.right
|
||||
|
||||
case .trailing:
|
||||
leadingContentInset = fullLeadingContentInset
|
||||
trailingContentInset = contentInsets.right
|
||||
imagePadding = titleInsets.right + imageInsets.left
|
||||
|
||||
default:
|
||||
leadingContentInset = fullLeadingContentInset
|
||||
trailingContentInset = fullTrailingContentInset
|
||||
imagePadding = .zero
|
||||
}
|
||||
|
||||
config.contentInsets = NSDirectionalEdgeInsets(top: topContentInset,
|
||||
leading: leadingContentInset,
|
||||
bottom: bottomContentInset,
|
||||
trailing: trailingContentInset)
|
||||
|
||||
config.imagePadding = imagePadding
|
||||
} else {
|
||||
config.contentInsets = NSDirectionalEdgeInsets(top: topContentInset,
|
||||
leading: fullLeadingContentInset,
|
||||
bottom: bottomContentInset,
|
||||
trailing: fullTrailingContentInset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
public func configureUIView(appearance: BaseAppearance<some ViewLayout>) {
|
||||
public extension UIView {
|
||||
func configureUIView(appearance: BaseAppearance<some ViewLayout>) {
|
||||
backgroundColor = appearance.backgroundColor
|
||||
layer.masksToBounds = true
|
||||
layer.maskedCorners = appearance.border.roundedCorners
|
||||
|
|
|
|||
|
|
@ -25,11 +25,15 @@ import UIKit
|
|||
|
||||
public final class DefaultConfigurableStatefulButton: StatefulButton, ConfigurableView, AppearanceConfigurable {
|
||||
|
||||
private var appearance: Appearance = .defaultAppearance
|
||||
|
||||
// MARK: - ConfigurableView
|
||||
|
||||
public func configure(with viewModel: ViewModel) {
|
||||
viewModel.willReuse(view: self)
|
||||
|
||||
stateViewModelMap = viewModel.stateViewModelMap
|
||||
|
||||
for (state, viewModel) in viewModel.stateViewModelMap {
|
||||
setTitle(viewModel.title, for: state)
|
||||
setImage(viewModel.image, for: state)
|
||||
|
|
@ -38,12 +42,15 @@ public final class DefaultConfigurableStatefulButton: StatefulButton, Configurab
|
|||
|
||||
apply(state: viewModel.currentState)
|
||||
|
||||
configureStatefulButton(appearance: appearance)
|
||||
|
||||
viewModel.didCompleteConfiguration(of: self)
|
||||
}
|
||||
|
||||
// MARK: - AppearanceConfigurable
|
||||
|
||||
public func configure(appearance: DefaultPositionAppearance) {
|
||||
self.appearance = appearance
|
||||
configureStatefulButton(appearance: appearance)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,9 +127,9 @@ extension StatefulButton {
|
|||
public func configureBaseStatefulButton(appearance: BaseAppearance<some ViewLayout, some BaseContentLayout>) {
|
||||
onStateChanged = { [weak self] in
|
||||
if let stateAppearance = appearance.stateAppearances[$0] {
|
||||
self?.configureUIButton(appearance: stateAppearance)
|
||||
self?.configureUIButton(appearance: stateAppearance, for: $0)
|
||||
} else if $0 != .normal, let stateAppearance = appearance.stateAppearances[.normal] {
|
||||
self?.configureUIButton(appearance: stateAppearance)
|
||||
self?.configureUIButton(appearance: stateAppearance, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ open class StatefulButton: BaseInitializableButton {
|
|||
configureDefaultActivityIndicator()
|
||||
}
|
||||
|
||||
updateAppearance(to: .loading)
|
||||
|
||||
activityIndicator?.startAnimating()
|
||||
} else {
|
||||
activityIndicator?.stopAnimating()
|
||||
}
|
||||
|
||||
updateAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +83,8 @@ open class StatefulButton: BaseInitializableButton {
|
|||
|
||||
var activityIndicatorShouldCenterInView = false
|
||||
|
||||
var stateViewModelMap: [State: BaseButtonViewModel] = [:]
|
||||
|
||||
var onStateChanged: ParameterClosure<State>?
|
||||
|
||||
// MARK: - Private properties
|
||||
|
|
@ -103,6 +105,18 @@ open class StatefulButton: BaseInitializableButton {
|
|||
super.setImage(image, for: state)
|
||||
}
|
||||
|
||||
open override func title(for state: UIControl.State) -> String? {
|
||||
stateViewModelMap[state]?.title ?? super.title(for: state)
|
||||
}
|
||||
|
||||
open override func image(for state: UIControl.State) -> UIImage? {
|
||||
stateViewModelMap[state]?.image ?? super.image(for: state)
|
||||
}
|
||||
|
||||
open override func backgroundImage(for state: UIControl.State) -> UIImage? {
|
||||
stateViewModelMap[state]?.backgroundImage ?? super.backgroundImage(for: state)
|
||||
}
|
||||
|
||||
// MARK: - UIControl override
|
||||
|
||||
open override var state: UIControl.State {
|
||||
|
|
|
|||
Loading…
Reference in New Issue