#ios #swift #button #swiftui
#iOS #быстрый #кнопка #свифтуи
Вопрос:
В SwiftUI есть несколько Button
инициализаторов, но все они требуют либо a String
, либо some View
в качестве параметра наряду с action
.
Однако внешний вид кнопки также можно настроить с помощью ButtonStyle
s, которые могут добавлять к ней пользовательские представления.
Давайте рассмотрим кнопку копирования со следующим значком:
Стиль, который я создал для кнопки, выглядит следующим образом:
struct CopyButtonStyle: ButtonStyle { init() {} func makeBody(configuration: Configuration) -gt; some View { let copyIconSize: CGFloat = 24 return Image(systemName: "doc.on.doc") .renderingMode(.template) .resizable() .frame(width: copyIconSize, height: copyIconSize) .accessibilityIdentifier("copy_button") .opacity(configuration.isPressed ? 0.5 : 1) } }
Это работает отлично, однако я должен инициализировать Button
пустую строку на сайте вызова:
Button("") { print("copy") } .buttonStyle(CopyButtonStyle())
Итак, вопрос в том, как я могу избавиться от пустой строки в параметре инициализации кнопки?
Потенциальное Решение
Мне удалось создать простое расширение, которое выполняет необходимую мне работу:
import SwiftUI extension Button where Label == Text { init(_ action: @escaping () -gt; Void) { self.init("", action: action) } }
Позвоните на сайт:
Button() { // Note: no initializer parameter print("copy") } .buttonStyle(CopyButtonStyle())
Но любопытно, правильно ли я использую Button
структуру, и для этого уже есть вариант использования, чтобы я мог избавиться от этого расширения.
Ответ №1:
Более простой способ, чем создание ButtonStyle
конфигурации, — это передать метку напрямую:
Button { print("copy") } label: { Label("Copy", systemImage: "doc.on.doc") .labelStyle(.iconOnly) }
Это также дает некоторые преимущества:
- По умолчанию кнопка синего цвета указывает на то, что ее можно нажать
- Никакого странного растягивания изображения, которое у вас сейчас есть
- Нет необходимости реализовывать, как изменяется непрозрачность при нажатии
Вы также можете преобразовать это в собственное представление:
struct CopyButton: View { let action: () -gt; Void var body: some View { Button(action: action) { Label("Copy", systemImage: "doc.on.doc") .labelStyle(.iconOnly) } } }
Называется так:
CopyButton { print("copy") }
Что в целом выглядит намного чище.
Комментарии:
1. У меня есть палитра других
ButtonStyle
s, которые могут не использовать символы SF или использовать текст, так что это было бы слишком нестандартным решением. Обратите внимание, что я хотел бы избавиться от параметра инициализатора, а не от поддержки стиля или создать полностью пользовательский тип. Но спасибо за ваш ответ!
Ответ №2:
Вот правильный способ для того, что вы пытаетесь сделать, вам не нужно создавать новый стиль кнопок для каждого вида кнопок, вы можете создать только одну и повторно использовать ее для любых других кнопок, которые вы хотите. Также я решил вашу проблему с растяжением изображения .scaledToFit()
.
struct CustomButtonView: View { let imageString: String let size: CGFloat let identifier: String let action: (() -gt; Void)? init(imageString: String, size: CGFloat = 24.0, identifier: String = String(), action: (() -gt; Void)? = nil) { self.imageString = imageString self.size = size self.identifier = identifier self.action = action } var body: some View { return Button(action: { action?() } , label: { Image(systemName: imageString) .renderingMode(.template) .resizable() .scaledToFit() .frame(width: size, height: size) .accessibilityIdentifier(identifier) }) .buttonStyle(CustomButtonStyle()) } } struct CustomButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -gt; some View { return configuration.label .opacity(configuration.isPressed ? 0.5 : 1.0) .scaleEffect(configuration.isPressed ? 0.95 : 1.0) } }
пример использования:
struct ContentView: View { var body: some View { CustomButtonView(imageString: "doc.on.doc", identifier: "copy_button", action: { print("copy") }) } }
Комментарии:
1. «Также я решил проблему растяжения вашего изображения» -gt; в этом нет необходимости, значок, который я использую, является пользовательским, с ним нет проблем с растяжением. Значок, представленный здесь, предназначен только для справки, вопрос только об API (программировании)
2. Я просто вижу код, о котором идет речь, в вопросе есть проблема растяжения! Ps: это мой стиль ответа, который я пытаюсь решить или переработать любую проблему, о которой идет речь. Ты можешь сделать это сам.
3. Никаких проблем, и спасибо, что решили ее и предложили свою версию. Для этого вопроса я только что заменил свой пользовательский значок (который идеально подходит) на значок по умолчанию, так что по-прежнему ясно, о чем идет речь.
4. Я уже ответил вам в своем последнем комментарии о моем стиле ответа! Так что не имеет значения, что вы смело говорите о том, о чем идет речь! И еще я упомянул: Ты делаешь это сам! Это значит, делай свой стиль! Я делаю свой стиль.
Ответ №3:
Вы можете использовать EmptyView
для этикетки, например
Button(action: { // Note: no initializer parameter print("copy") }, label: { EmptyView() }) .buttonStyle(CopyButtonStyle())
но упаковка его в пользовательский тип кнопки (как показано в другом ответе) более предпочтительна с точки зрения повторного использования и удобочитаемости кода.
Комментарии:
1. Тем не менее, нужно добавить
EmptyView
сайт для звонков. Я бы просто предпочел избавиться от него. Похоже, расширение и метод инициализации являются здесь простейшими решениями.