SwiftUI LabelStyle, проверяет, существует ли Configuration.icon?

В своем приложении я размещаю кнопку с символом шестеренки в верхнем левом углу; он используется для открытия листа настроек.

      Button { withAnimation { showSettingsSheet.toggle() }} label: {
  Label("Settings", systemImage: "gearshape")
    .labelStyle(.iconOnly)
}

В первой бета-версии iOS 17 у меня были сообщения о том, что кнопка «Настройки» не отображалась и не реагировала на нажатия. У меня не было возможности попробовать это самому, но я подозреваю, что, возможно, символ SF не загрузился, и поскольку я использую стиль метки, нечего было отображать или реагировать на касания. Это не проблема в iOS 17 beta 2.

Я хочу обращаться с этим более изящно в будущем. Я думаю создать SafeIconOnlyLabelStyle, который обычно отображает значок, но возвращается к пустой конфигурации title.icon.

      struct SafeIconOnlyLabelStyle: LabelStyle {
  @ViewBuilder func makeBody(configuration: Configuration) -> some View {
    if configuration.icon == <<WHAT SHOULD configuration.icon BE COMPARED TO>> {
      Label(configuration)
        .labelStyle(.iconOnly)
    } else {
      Label(configuration)
    }
  }
}

Как я могу проверить, что он существует и действителен?

Обновлять

В отличие от UIImage, NSImage и CGImage, которые возвращают необязательный параметр для тестирования, SwiftUI всегда возвращает представление изображения. Если вы передадите в Image плохое имя, оно все равно добавит в иерархию представление изображения, только одно без высоты и ширины.

      Label("Title", systemName: "badName")

и

      Label { 
  Text("Title") 
} icon: {
    Image(systemImage: "badName")
}

эквивалентны. Запуск на iOS и использование.titleAndIconLabelStyle, можно было бы ожидать, что эквивалент будет:

      HStack {
  Image(systemImage: "badName").frame(width: .zero, height: .zero)
  Text("Title")
}

Когда.iconOnlyLabelStyle используется, упрощенная метка будет представлять собой просто значок, например:

      Image(systemImage: "badName").frame(width: .zero, height: .zero)

Когда эта иерархия используется для метки кнопки, кнопка отображается без заголовка или значка. Это может быть проблематично, если источник проблемы находится вне вашего контроля.

Моим первым решением было создать SafeIconOnlyLabelStyle, который будет использоватьGeometryReaderчтобы рассчитать размерconfiguration.iconи отобразитьconfiguration.titleкогда размер был.zero.Это сработало нормально; однако это может стать потенциальным источником будущих ошибок, если Apple решит внести изменения.

Вместо этого, основываясь на этом ответе , я создал собственное представление SafeLabel, которое использует заголовок вместо значка, когда значок не существует.

      public struct SafeLabel: View {
  #if os(macOS)
  typealias SystemImage = NSImage
  #elseif os(iOS)
  typealias SystemImage = UIImage
  #endif

  private var title: Text
  private var icon: Image?

  public init(_ titleKey: LocalizedStringKey, systemImage name: String) {
    self.title = Text(titleKey)

    if let image = fetchImage(systemName: name) {
      #if os(macOS)
      icon = Image(nsImage: image)
      #elseif os(iOS)
      icon = Image(uiImage: image)
      #endif
    }
  }

  @MainActor public var body: some View {
    Label {
      title
    } icon: {
      if let icon {
        icon
      } else {
        Text("\(title)")
      }
    }
  }
    
  private func fetchImage(systemName name: String) -> SystemImage? {
    #if os(macOS)
    guard let image = NSImage(systemImageName: name) else { return nil }
    #elseif os(iOS)
    guard let image = UIImage(systemName: name) else { return nil }
    #endif
    return image
  }
}

Это устраняет мои опасения по поводу предотвращения исчезновения меток (и кнопок), если изображение недоступно.

0 ответов

Другие вопросы по тегам