InputBarAccessoryView icon indicating copy to clipboard operation
InputBarAccessoryView copied to clipboard

Swift UI Support

Open fpedro23 opened this issue 4 years ago • 5 comments

Currently trying to implement a UIViewRepresentable of InputBarAccessoryView with no luck. Is there any branch or project that I could check out that had implemented this feature successfully?

fpedro23 avatar Jun 14 '20 23:06 fpedro23

Could you please check SwiftUI example in MessageKit example app? https://github.com/MessageKit/MessageKit

Kaspik avatar Aug 26 '20 20:08 Kaspik

@fpedro23 did you get any further with your attempt?

AndrewSB avatar Oct 04 '20 05:10 AndrewSB

Yep, heres the code:

struct CommentInputBar: UIViewRepresentable {
    
    @Binding
    var text: String
    
    @Binding
    var size: CGSize
    
    var onSendPerform: (String) -> Void
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> InputBarAccessoryView {
        let bar = iMessageInputBar()
        bar.backgroundView.backgroundColor = .acBackground
        bar.delegate = context.coordinator
        DispatchQueue.main.async {
            bar.inputTextView.placeholderLabel.text = "Write a review..."
        }
        return bar
    }
    
    func updateUIView(_ uiView: InputBarAccessoryView, context: Context) {
    }
    
    class Coordinator: InputBarAccessoryViewDelegate {
        
        var control: CommentInputBar
        
        init(_ control: CommentInputBar) {
            self.control = control
        }
        
        func inputBar(_ inputBar: InputBarAccessoryView, didChangeIntrinsicContentTo size: CGSize) {
            control.size = size
        }
        
        func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) {
            control.onSendPerform(text)
            inputBar.inputTextView.text = ""
        }
    }
}
struct YourCustomView: View {

    @State
    var size: CGSize = CGSize(width: 0, height: 50)
    
    var body: some View {
                CommentInputBar(text: $text, size: $size, onSendPerform: {
                    //Do your action
                })
                .frame(height: size.height)

      }
} 

It is important to follow this @Binding size approach since SwiftUI and the internal constraints of InputBarAccessoryView seem to conflict and the height of the Accessory view is not updated as the user types, thats why I manually set the height of the frame. Let me know if you have any other questions.

fpedro23 avatar Oct 05 '20 15:10 fpedro23

This is awesome, thanks for sharing!

I haven't seen this strategy of binding a size to a SwiftUI control, and listening to UIKit events, is it something you found elsewhere?

AndrewSB avatar Oct 08 '20 18:10 AndrewSB

I came up with this solution after trying for 6 hours straight to figure out why the bar had such odd sizing. I don't think it's a standard approach, I just did it this way for this particular view since there are some internal constraints that I do not control and InputBarAccessoryViewDelegate makes it really easy to listen for size changes.

fpedro23 avatar Oct 08 '20 20:10 fpedro23