Reputation: 337
Right now, I am in the process of converting from UIKit to SwiftUI. In UIKit, there is a native Close, X-Styled Button - UIButton.ButtonType.close,
like shown below:
I wanted to find the equivalent of this in SwiftUI, if built in to SwiftUI already. It is understandable if Apple hasn't gotten around to building/converting this yet. I see this also in the Apple Maps App, which I believe is built in SwiftUI, like shown below (on the bottom right corner of the panel):
If there isn't a built in button styling, how would one go about creating a View for this close button, which would adapt to light and dark mode? Thank you so much!
Edit: In UIKIt's Storyboard Editor, here is what I am looking for:
Upvotes: 7
Views: 2670
Reputation: 647
A condensed version of the UIViewRepresentable
approach.
struct CloseButton: UIViewRepresentable {
private let action: () -> Void
init(action: @escaping () -> Void) { self.action = action }
func makeUIView(context: Context) -> UIButton {
let button = UIButton(type: .close, primaryAction: UIAction { _ in action() })
for axis in [NSLayoutConstraint.Axis.horizontal, .vertical] {
button.setContentCompressionResistancePriority(.required, for: axis)
button.setContentHuggingPriority(.required, for: axis)
}
return button
}
func updateUIView(_ uiView: UIButton, context: Context) {}
}
Upvotes: 1
Reputation: 161
You can embed a UIKit UIButton
with UIViewRepresentable
.
struct CloseButton: UIViewRepresentable {
private let action: () -> Void
init(action: @escaping () -> Void) {
self.action = action
}
func makeUIView(context: Context) -> UIButton {
let button = UIButton(type: .close)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .vertical)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentHuggingPriority(.required, for: .vertical)
button.addTarget(context.coordinator, action: #selector(Coordinator.perform), for: .primaryActionTriggered)
return button
}
func updateUIView(_ uiView: UIButton, context: Context) {
context.coordinator.action = action
}
func makeCoordinator() -> Coordinator {
Coordinator(action: action)
}
class Coordinator {
var action: () -> Void
init(action: @escaping () -> Void) {
self.action = action
}
@objc func perform() {
action()
}
}
}
and then
CloseButton {
// dismiss()
}
Example:
SomeView()
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
CloseButton {
dismiss()
}
.disabled(isBusy) // SwiftUI modifiers work fine.
}
}
Upvotes: 7
Reputation: 55865
It is not currently possible to use system button types in SwiftUI including the close button. I’ve submitted FB10380135 to request this addition.
In the meantime, you could make a Button look like the system close button. Mike Stern, an Apple Design Evangelist, noted in an Ask Apple Q&A:
The modal close button uses the "xmark" SF Symbol at 15pt bold (regular size symbol, not large or small variant) and a 30×30pt circle. The hit area is likely bigger as we typically go for at target size that's at least 44×44pt.
Also note the close button doesn’t change size as the dynamic type size increases/decreases. Do be sure to make its accessibility label “close” and add support for the large content viewer so people using accessibility text sizes can tap and hold the button to reveal a large xmark symbol with the word Close underneath.
I personally would recommend utilizing UIViewRepresentable
to add a real close UIButton
button though as opposed to trying to replicate it exactly - see the answer provided by MMP0.
Upvotes: 5
Reputation: 120052
You can use the xmark.circle.fill
symbol as the system image:
⚠️ Note: there is a difference between xmark.circle.fill
and x.circle.fill
Upvotes: 3
Reputation: 258443
SwiftUI does not use concept of "button type", instead you can construct it by yourself, like
Button(action: {}) {
Image(systemName: "xmark.circle.fill") // << base !!
.resizable()
.frame(width: 32, height: 32) // << for demo
.foregroundColor(.gray)
}
*with any other modifiers as you wish
Xcode 13.4 / iOS 15.5
Upvotes: 8