-2
UIAction.captureTextFromCamera(responder: context.coordinator, identifier: nil)

This method must be placed in a Menu before it can be used. What if I want to call this method when I press the Button?

And I wanna use it in the SwiftUI, like this

@State var text = ""

Text(text)

Menu {

                Button(action: {

                    // TODO: support live text

                }) {

                    Label("Live Text", systemImage: "camera.viewfinder")

                }

            } label: {

                Text("Hi")

            }
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
  • `UIButton` conforms to `UIResponder` too, I think, so it should work – aheze Sep 25 '21 at 04:36
  • It needs `UIResponder & UIKeyInput` it won't work directly in a SwiftUI `Button` because it doesnt have anywhere to put the text. You have to use a UIKit option that has both – lorem ipsum Sep 25 '21 at 09:38
  • @Yunnosch Yes, I changed a new question. Because this question gets negative points. So I cannot question a new one. – Underthestars-zhy Feb 02 '22 at 13:36
  • Thanks for confirming. I undo that by rolling back. Please create a new question by using the "Ask Question" button. (I suspect that you might appreciate this information: https://stackoverflow.com/help/question-bans and https://stackoverflow.com/help/asking-rate-limited ; in these cases fundamentally changing an existing quesiton is not an accepted path) – Yunnosch Feb 02 '22 at 13:37
  • Let me point out the non-obvious detail that deleting negative-scored questions does NOT help with any question-asking-obstacle. On the contrary, the best way out of it is to improve existing questions, including to first improve and then undelete some which you have deleted. Because that is the only way to have some at least 0-scored questions, or better. Deleting this one one would only push you away from a chance to ask more questions. Feel free to ping me ( @Yunnosch in a comment ) on any question you have improved. I will have a well-meaning look for noticable improvement. – Yunnosch Feb 02 '22 at 14:33

1 Answers1

2
import SwiftUI
@available(iOS 15.0, *)
struct ScanTextView: View {
    @State var text: String = ""
    @State var message: String = ""
    var body: some View {
        VStack {
            Text(message)
            HStack{
                TextField("Enter text",text: $text)
                ScanTextView_UI(text: $text, type: .buttonMenu,imageSystemName: "ellipsis.circle", additionalActions: [
                    //https://developer.apple.com/documentation/uikit/uiaction
                    UIAction(title: "Refresh") { (action) in
                        //Just sample
                        self.message = "refresh"
                    },
                    UIAction(title: "Anything", image: UIImage(systemName: "checkmark")) { (action) in
                        //Just sample
                        self.message = "anything"
                    },
                    UIAction(title: "Clear message") { (action) in
                        //Just sample
                        self.message = ""
                    }
                ])
            }.border(Color.red)
            TextField("Enter text",text: $text)
                .border(Color.yellow)
                .toolbar(content: {
                    ToolbarItem(placement: .keyboard, content: {
                        ScanTextView_UI(text: $text, type: .buttonMenu)
                    })
                })
            ScanTextView_UI(text: $text, type: .textField, additionalActions: [
                UIAction(title: "Anything", image: UIImage(systemName: "checkmark")) { (action) in
                    //Just sample
                    self.message = "anything"
                }
            ]).border(Color.orange)
            HStack{
                TextField("Enter text",text: $text)
                ScanTextView_UI(text: $text, type: .button)
            }.border(Color.green)
            
        }
    }
}
@available(iOS 15.0, *)
struct ScanTextView_UI: UIViewRepresentable {
    @Binding var text: String
    let type: Types
    var imageSystemName: String = "text.viewfinder"
    var additionalActions: [UIAction] = []
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    func makeUIView(context: Context) -> some UIView {
        let textFromCamera = UIAction.captureTextFromCamera(responder: context.coordinator, identifier: nil)
        
        let image = UIImage(systemName: imageSystemName)
        
        //button
        let button = UIButton(frame: .zero, primaryAction: textFromCamera)
        button.setImage(image, for: .normal)
        //buttonMenu
        // A UIButton can hold the menu, it is a long press to get it to come up
        let buttonMenu = UIButton()
        
        var temp: [UIAction] = [textFromCamera]
        
        for elem in additionalActions{
            temp.append(elem)
        }
        
        
        let cameraMenu = UIMenu(children: temp)
        buttonMenu.setImage(image, for: .normal)
        buttonMenu.menu = cameraMenu
        
        //TextField
        // Or a textField
        let toolbarItem = UIBarButtonItem(title: nil, image: image, primaryAction: textFromCamera, menu: nil)
        
        var temp2: [UIBarButtonItem] = [toolbarItem]
        
        for elem in additionalActions{
            temp2.append(UIBarButtonItem(title: elem.title, image: elem.image, primaryAction: elem, menu: nil))
        }
        let textField = UITextField()
        let bar = UIToolbar()
        bar.items = temp2
        bar.sizeToFit()
        textField.inputAccessoryView = bar
        textField.placeholder = "Enter text"
        textField.delegate = context.coordinator
        textField.text = text
        
        var result: UIView = UIView()
        switch type {
        case .textField:
            result = textField
        case .buttonMenu:
            result = buttonMenu
        case .button:
            if !additionalActions.isEmpty{
                result = buttonMenu
            }else{
                result = button
            }
        }
        
        return result
    }
    func updateUIView(_ uiView: UIViewType, context: Context) {
        if uiView is UITextField{
            (uiView as! UITextField).text = text
        }
    }
    //Making the Coordinator a UIResponder as! UIKeyInput gives access to the text
    class Coordinator: UIResponder, UIKeyInput, UITextFieldDelegate{
        var hasText: Bool{
            !parent.text.isEmpty
        }
        
        let parent: ScanTextView_UI
        
        init(_ parent: ScanTextView_UI){
            self.parent = parent
        }
        func insertText(_ text: String) {
            //Update the @Binding
            parent.text = text
        }
        
        func deleteBackward() { }
        // MARK: UITextFieldDelegate
        func textFieldDidBeginEditing(_ textField: UITextField) {
            parent.text = textField.text ?? ""
        }
    }
    enum Types{
        case textField
        case buttonMenu
        case button
    }
}
@available(iOS 15.0, *)
struct ActionMenuView_Previews: PreviewProvider {
    static var previews: some View {
        ScanTextView()
    }
}

enter image description here

lorem ipsum
  • 21,175
  • 5
  • 24
  • 48
  • VStack { Text(text) Menu { ScanTextView_UI(text: $text, type: .button) } label: { Text("2") } } it not work – Underthestars-zhy Sep 25 '21 at 10:34
  • 1
    @Underthestars-zhy No it doesn't it looks like there are underlying conflicts. You have to use the .buttonMenu option and if you have more actions you have to create them programatically. – lorem ipsum Sep 25 '21 at 11:21
  • 1
    @Underthestars-zhy I added a little sample – lorem ipsum Sep 25 '21 at 11:48
  • @Iroem ipsum it seems that i muts use uikit menu, is there any way that i can combine the UIAction with the SwiftUI Menu – Underthestars-zhy Sep 25 '21 at 11:57
  • 1
    @Underthestars-zhy Doubt it... You can add elements to the UIKit Menu easily but I don't think you can combine. After all SwiftUI elements are just a simpler version of there UIKit counterpart. Did you see the code change? Where you can add actions? – lorem ipsum Sep 25 '21 at 12:00
  • @Underthestars-zhy that is pretty shady. It won’t make your reputation any better for sure to unmark answers so you can “clean up” your profile. – lorem ipsum Feb 02 '22 at 14:13