Search code examples
swiftswiftuiuiactionsheet

Add Image and Text to Actions Sheet's Alert Button


I want to be able to add an icon and text to the AlertButton but the type is a type Text?

struct NavigationAddItem: View {
    @State var showActionView = true

    var actionSheet: ActionSheet {
        ActionSheet(title: Text("Select an action"), message: nil, buttons: [
            .default(Text("Option A"), action: {
                // TODO: Enter Option A action
            }),
            .default(Text("Option B"), action: {
                // TODO: Enter Option B action
            }),
            .cancel()
        ])
    }

    var body: some View {
        Button(action: {
            self.showActionView.toggle()
        }) {
            Image(systemName: "plus")
                .font(.system(size: 24))
        }
        .actionSheet(isPresented: $showActionView, content: {
            self.actionSheet
        })
    }
}


struct NavigationItems_Previews: PreviewProvider {
    static var previews: some View {
        NavigationAddItem(showActionView: true)
    }
}

This code gives the the action sheet but I want to add a image to the left of the text.

Current: enter image description here

Wanted: enter image description here


Solution

  • I don't think that it is currently possible to define your own View for the Button in an ActionSheet.

    Looking at the code for the ActionSheet we see the following:

    @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
    @available(OSX, unavailable)
    public struct ActionSheet {
    
        /// Creates an action sheet with the provided buttons.
        public init(title: Text, message: Text? = nil, buttons: [ActionSheet.Button] = [.cancel()])
    
        /// A button representing an operation of an action sheet presentation.
        public typealias Button = Alert.Button
    }
    

    This shows that the Button that the ActionSheet uses is typealiased to Alert.Button

    If we look at the the struct for Alert we can see the following methods:

    /// A storage type for an alert presentation.
    @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
    public struct Alert {
    
        /// Creates an alert with one button.
        public init(title: Text, message: Text? = nil, dismissButton: Alert.Button? = nil)
    
        /// Creates an alert with two buttons.
        ///
        /// - Note: the system determines the visual ordering of the buttons.
        public init(title: Text, message: Text? = nil, primaryButton: Alert.Button, secondaryButton: Alert.Button)
    
        /// A button representing an operation of an alert presentation.
        public struct Button {
    
            /// Creates an `Alert.Button` with the default style.
            public static func `default`(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
    
            /// Creates an `Alert.Button` that indicates cancellation of some
            /// operation.
            public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
    
            /// Creates an `Alert.Button` that indicates cancellation of some
            /// operation.
            ///
            /// - Note: the label of the button is automatically chosen by the
            /// system for the appropriate locale.
            public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button
    
            /// Creates an `Alert.Button` with a style indicating destruction of
            /// some data.
            public static func destructive(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
        }
    }
    

    Notice that each of the functions that create Alert.Button, they are: default, cancel and destructive, only take a label of type Text and an action of type (() -> Void)?. This means that you can only pass a view that conforms to Text.

    So trying to pass a view that doesn't conform to Text won't work, as you have already discovered.