This week I decided to tell you about the topic I became a big fan of lately, but I promise to continue my problem-solving series next week. Today I’d like to give you a short overview of SwiftUI, why is it awesome and tell you how you can implement UIKit components in your SwiftUI project and why this knowledge is crucial at least for the time while Apple is not fully finished with development of SwiftUI.
Alright, let’s get started. First of all, what’s SwiftUI? Apple calls it “an innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift”. Previously there was only one way of building UIs for iOS applications: UIKit. UIKit allowed developers to create interfaces, the frontend of the application, using something what’s called Storyboards, where developers were able to simply put the components they wanted to see on the page or components could’ve been placed on the page programmatically, which was the approach I liked better, but still, both of them were far from being super convenient. And I have a feeling that at some point Apple understood that and came up with SwiftUI, which I like a lot, not going to lie.
For me, developing UIs in SwiftUI seems very similar to developing things in React, where you have certain component and you are allowed to use them everywhere in your app, except that in case with Apple’s framework you have a huge amount of built-in components like Text, Image, TextField and many more, which you can use at your own discretion, for example use it as it is or create more complex components using built-in ones.
But, despite a lot of cool features that we get as the result of SwiftUI having a declarative syntax in comparison to imperative, SwiftUI is a pretty new framework that still lacks support for some iOS component types that were widely used in UIKit. And while Apple is working on expanding the number of available components, they made it pretty easy to use yet unavailable in SwiftUI components by allowing developers to create them using the ones that already exist in UIKit. And yes, lucky you, I am going to show you how to do it in this blog post.
Recently I was working on the development of a sign up form for one of my applications and one of the required parts was “About” section, since I hope that most of my users will have more than 2 words to tell about themselves, I decided that TextField won’t fit their great stories, so I felt a need in some kind of text view, unfortunately, nothing like that is implemented in SwiftUI, but luckily for me there is a UITextView in UIKit and a way to implement it in SwiftUI.
So the first thing I was to do is create a struct that will hold my TextView, to let SwiftUI know that it’s a component it can use, we need to make sure this struct conforms to UIViewRepresentable protocol.
To implement that, our struct needs to have 2 mandatory functions, which are: makeUIView that takes context as an argument and returns UITextView in our case and updateUIView which is not used at all most of the times.
As you can see, inside of my makeUIView I simply created an instance of UITextView and programmatically set some parameters, by the way, placeholder is one of the parameters I pass to this struct, when calling it, along with text binding:
Bindings are another cool feature of SwiftUI, but it’s a topic for another blog.
The most interesting line inside of makeUIView is line where we set textView’s delegate to context’s coordinator. You might ask where this coordinator is coming from? It’s easy, we have to create it ourselves:
Coordinator class has to be of type NSObject and conform to UITextViewDelegate protocol, which defines a set of optional methods you can use to receive editing-related messages for UITextView objects, this will help us to connect our textView component with SwiftUI. Inside of our coordinator we need to initialize all the variables which is a simple process and I won’t go over it and we also can use basic UITextViewDelegate’s methods like textViewDidChange, textViewShouldBeginEditing and textViewShouldEndEditing. Here is my textViewDidChange method for example:
It might look a bit overcomplicated, but since standard UITextView doesn’t have placeholders I had to implement “placeholders” myself, but other than that this method simply passes new values to our text binding every time user types something in.
You can implement as many methods you want as long as they conform to UITextViewDelegate protocol. Here is how my Coordinator looks now:
In addition to textViewDidChange method, I also have textViewShouldBeginEditing and textViewShouldEndEditing which are simply changing the frame color on edit, and textViewDidChangeSelection which allows user to exit TextView on tap anywhere outside of the view.
One important thing to remember is that every time you create a coordinator, you need to connect it with your newly created view struct, this can be easily done by calling a function called makeCoordinator that takes no argument and simply calls our coordinator with all the required parameters provided like this:
And after that, you are free to pass this coordinator as a delegate to the instance of UITextView you created.
And voila, this is the whole process of creating SwiftUI component with UIKit. As I mentioned before, my newly created component takes two parameters and here is the way to call this component in SwiftUI:
And as a final note, here is how my newly created component looks in action:
Hope you liked this tutorial! Since this is an unusual format for me, I would appreciate any feedback, which you are more than welcome to leave in the comments!