Home > Blockchain >  ternary operations for labels does not work
ternary operations for labels does not work

Time:07-07

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
            }
        }
    }
}
  • Related