I am trying to assign a custom label style based on my icon alignment value, that is left or right. if it is left, the icon comes before text, if it is right the icon comes after it. These are my custom label styles:
var iconAlignment: IconAlignment
enum IconAlignment {
case left
case right
}
struct IconFirstLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.icon
configuration.title
}
}
}
struct IconFirstLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.title
configuration.icon
}
}
}
I want to do this now:
Label { Text("hi") } icon : {Image(systemName: "plus")}
.labelStyle(iconAlignment == .left ? IconFirstLabelStyle() : TextFirstLabelStyle())
but this causes an issue and Xcode tells me these are two different structs, even though they are inheriting the same protocol. Is there any way to use ternary here, or should I go a long approach with if else?
CodePudding user response:
You say "even though they are inheriting the same protocol"—that does not display the understanding that some
, and the ternary operator, each require one type. Such as this:
labelStyle(
iconAlignment == .left
? AnyStyle(IconFirstLabelStyle())
: AnyStyle(TextFirstLabelStyle())
)
import SwiftUI
/// A type-erased "`Style`".
public struct AnyStyle<Configuration> {
private let makeBody: (Configuration) -> AnyView
}
// MARK: - public
public extension AnyStyle {
init(makeBody: @escaping (Configuration) -> some View) {
self.makeBody = { .init(makeBody($0)) }
}
func makeBody(configuration: Configuration) -> some View {
makeBody(configuration)
}
}
// MARK: - LabelStyle
extension AnyStyle: LabelStyle where Configuration == LabelStyleConfiguration {
public init(_ style: some LabelStyle) {
self.init(makeBody: style.makeBody)
}
}
// MARK: - ButtonStyle
extension AnyStyle: ButtonStyle where Configuration == ButtonStyleConfiguration {
public init(_ style: some ButtonStyle) {
self.init(makeBody: style.makeBody)
}
}
// etc.
CodePudding user response:
Ternary operator requires both parts to be of the same type.
A simple solution for this is just to use one style type and inject condition via argument, like
Label { Text("hi") } icon : {Image(systemName: "plus")}
.labelStyle(IconAlignedLabelStyle(alignIcon: iconAlignment))
struct IconAlignedLabelStyle: LabelStyle {
var alignIcon = IconAlignment.left // << default one !!
func makeBody(configuration: Configuration) -> some View {
HStack {
if let alignIcon == .left {
configuration.icon
configuration.title
} else {
configuration.title
configuration.icon
}
}
}
}