[英]SwiftUI: Button without Label/String in the initializer but with ButtonStyle
SwiftUI has a few Button
initializers, but all of them require either a String
or some View
as the parameter alongside with the action
. SwiftUI 有一些
Button
初始化器,但它们都需要一个String
或some View
作为参数以及action
。
However, the button's appearance can also be customized with the help of ButtonStyle
s which can add custom views to it.但是,按钮的外观也可以在
ButtonStyle
的帮助下进行自定义,它可以添加自定义视图。
Let's consider a Copy button with the following icon:让我们考虑一个带有以下图标的复制按钮:
The style I've made for the button looks as follows:我为按钮制作的样式如下所示:
struct CopyButtonStyle: ButtonStyle {
init() {}
func makeBody(configuration: Configuration) -> 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)
}
}
It works perfectly, however, I have to initialize the Button
with an empty string at call site:它工作得很好,但是,我必须在调用站点用一个空字符串初始化
Button
:
Button("") {
print("copy")
}
.buttonStyle(CopyButtonStyle())
So, the question is how can I get rid of the empty string in the button's initialization parameter?那么,问题是如何摆脱按钮初始化参数中的空字符串?
Potential Solution潜在解决方案
I was able to create a simple extension that accomplishes the job I need:我能够创建一个简单的扩展来完成我需要的工作:
import SwiftUI
extension Button where Label == Text {
init(_ action: @escaping () -> Void) {
self.init("", action: action)
}
}
Call site:调用站点:
Button() { // Note: no initializer parameter
print("copy")
}
.buttonStyle(CopyButtonStyle())
But curious, whether I'm using the Button
struct incorrectly and there is already a use-case for that, so that I can get rid of this extension.但是很好奇,我是否错误地使用了
Button
结构并且已经有一个用例,这样我就可以摆脱这个扩展。
An easier way than making a ButtonStyle
configuration is to pass in the label directly:比进行
ButtonStyle
配置更简单的方法是直接传入 label:
Button {
print("copy")
} label: {
Label("Copy", systemImage: "doc.on.doc")
.labelStyle(.iconOnly)
}
This also comes with some benefits:这也带来了一些好处:
You could also refactor this into its own view:您还可以将其重构为自己的视图:
struct CopyButton: View {
let action: () -> Void
var body: some View {
Button(action: action) {
Label("Copy", systemImage: "doc.on.doc")
.labelStyle(.iconOnly)
}
}
}
Called like so:像这样调用:
CopyButton {
print("copy")
}
Which looks much cleaner overall.整体看起来更干净。
Here is a right way for what you are trying to do, you do not need make a new ButtonStyle for each kind of Button, you can create just one and reuse it for any other Buttons you want.这是您尝试做的正确方法,您不需要为每种按钮创建一个新的 ButtonStyle,您可以只创建一个并将其重用于您想要的任何其他按钮。 Also I solved your Image stretching issue with
.scaledToFit()
.我还用
.scaledToFit()
解决了您的图像拉伸问题。
struct CustomButtonView: View {
let imageString: String
let size: CGFloat
let identifier: String
let action: (() -> Void)?
init(imageString: String, size: CGFloat = 24.0, identifier: String = String(), action: (() -> 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) -> some View {
return configuration.label
.opacity(configuration.isPressed ? 0.5 : 1.0)
.scaleEffect(configuration.isPressed ? 0.95 : 1.0)
}
}
use case:用例:
struct ContentView: View {
var body: some View {
CustomButtonView(imageString: "doc.on.doc", identifier: "copy_button", action: { print("copy") })
}
}
You can use EmptyView
for label, like您可以将
EmptyView
用于 label,例如
Button(action: { // Note: no initializer parameter
print("copy")
}, label: { EmptyView() })
.buttonStyle(CopyButtonStyle())
but wrapping it in custom button type (like shown in other answer) is more preferable from re-use and code readability point of view.但是从重用和代码可读性的角度来看,将其包装在自定义按钮类型中(如其他答案所示)更可取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.