UIKit Integration with SwiftUI

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this year 2020 at WWDC Apple started filling the gaps and introduced new Swift UI specific solutions for things like map get progress views and activity indicators there are still some cases where you have a legacy view that you created in UIKit and you want to use that in your own project or perhaps you want to use an image and want to use the new photos UI framework to pick that photo and the alert view in swift UI still doesn't allow you to have a text field hi my name is Stewart Lynch in this video we're going to discover how you can use UI get specific views and view controllers within your own swift UI projects the solution is to use a UI view representable or a UI view controller representable to have swift UI and UI kit interoperability if this is something you want to learn then keep watching what you're looking at here is a UI kit solution that has those three things that I mentioned in the introduction at the top is a custom gauge that I took from one of Paul Hudson's videos it's designed in UI kit and when I tap this button I have a cycle through from 0 to 100 by 20 and as it does the needle moves smoothly the second button displays a photo picker from where I can select an image and have it replace the gray box on the main screen this uses the new photos UI in iOS 14 and there's currently no Swift UI equivalent in the final example when I tap the button to enter a name that presented with an alert with a text field and after I enter my name and submit the text on my main screen changes to reflect what I entered this type of alert is currently not possible in Swift UI so what I'm going to do today is build an almost identical swift UI app that will allow me to use these three UI kit items in that app you can download the source code for the uikit app and the starter project for our swift UI version from the link in the description below if you want to follow along though you will have to be running Xcode version 12 for this video I'm running beta to the principles are the same for iOS 13 and Xcode 11 but I'll be using the photos UI framework and that does require iOS 14 before I look at the swift Uihlein starter project let's take a quick look at the source code for the uikit app I've kept the code all in view controller for convenience sake but this is not necessarily how I would recommend you structure your apps the app is designed programmatically so no storyboard I've created a number of controls that represent our UI the first creates an instance of the custom gauge view it's not necessary to understand how this UI view was created but if you're interested you can check out the code in the gauge view Swift file the position of the needle is controlled by the value property every second one of our controls is a button with a target that performs a task the setup function takes care of laying them out on the screen in a vertical stack view the functions are what are required to perform our actions the move gauge function simply updates the gauge views value property by 20 using a time interval with an animation the gap image function uses the photos UI framework to select an image from our photos library and an extension of the view controller sets the image on our view to that selection if you're interested in finding out how to use the pH picker view controller I suggest that you watch the WWDC session and I'll leave a link in the description below the code here is basically taken directly from that session and finally the shoulder is a standard implementation of the UI alert controller with a text field it uses a title a message and a placeholder for the alert and when submitted the alert text on our main view is updated we're going to be reusing a lot of this code in our Swift Eli project so I'm going to keep this app open as I code now let's take a look at the starter project for the swift UI UI kit integration as you would expect the layout is much easier to do because it's Swift UI I have a placeholder here for the engage view and for the image and the image is currently Neel so a rectangle is being displayed when we pick an image it will be placed in this spot with the same frame and scaled to fill like our UI kit solution the three buttons all call functions similar to our UI kit solution but they are currently empty so it's our job to complete them the first task is actually the easiest one we want to use the gauge view you I give you in our project so the first thing we do is drag it from our UI kit solution into our project making sure that we have copy item if needed selected now we need to create a swift UI view that will represent this UI kit view the solution for that is to create a file that conforms to UI view representable so let's do that we don't need the boilerplate code from a swift UI file let's just choose a regular Swift file and I'm going to call it the aged view sui this is a swift di view so I have to change the import to swift UI here now we need to create a struct that will conform to UI view representable and I'll call my struck the same as I call the file engage view Sui and this is the swifty live you that we will have be able to use to display our Gage and right away we get an error type gage view Sui does not conform to protocol UI view representable if you choose to fix the issue it presents you with a type alias that is asking you for the type that you want to represent so in our case that is gage view if you save this file you still get an error with an option to fix again this time as we let Xcode do the fix it creates two functions one for make UI view and another for update UI view and now that those two stubs have been created we can actually delete the type alias it was only created to help Xcode know how to create those two functions make UI view is where you create the instance of your view the context contains your swift UI's environment animation transactions and something called the coordinator that will not need for this simple view but we will need for our next two examples so I'll wait until that time before I give an explanation so with make UI view we'll create an instance of our gauge view we can check out our UI kit version first to see how we created the view we can do it the same way as we did it in UI kit what I don't need are those constraints so I'll just copy and paste and remove this constraints now the second function will send updates to our UI kit version and that will be the new value to change the needle position this function will react to any changes and update the UI kit version this means that if the swift UI view here has a binding to a value and it changes it will force an update of the parent view well then what in our case is going to change it's the value if we create a binding for a value that represents the engaged you we can update it from our content views action so let's do that we'll create a binding for an INT and we'll call it value and then within our update UI view function we can update the UI view which is our gauge view with that same one-second animation that we did in UI kit now back in content view we need to create the state variable for our value that we can pass into our gauge view as a binding for updating we'll initialize that as 0 then we can replace our circle with our new gauge view SC UI passing on that state variable as a binding we can resume our canvas and see that the gates view is shown and if we preview our dial goes to 0 now all that is needed is to code the move gauge function for our button well this is the same as what we did in the UI can view controller I'll just copy that code and paste it into our function but we can remove the animation here because we are handling that within our update view function and since we're updating the value itself we can remove the gauge view reference tapping on the button updates the view as expected we're done okay let's move on to try and represent our new photo picker this time instead of representing a view we're going to represent a view controller in fact the new pH picker view controller so let's get started with that we know that this is not a swift UI view it's a view controller and as with the last example we need to create a swift UI view that will represent that view controller but instead of adhering to UI view representable we adhere to UI view controller representable protocol let's start by creating a new swiftie live file that I will call pH picker view I'll change the import to swift UI and because we're going to be using the photos UI framework we need to import that too let's start our struct using the UI view controller representable and just as the UI view representable counterpart we can let Xcode fix the error we'll let it create the type alias and we'll assign it the UI kids pH picker view controller will save the file and let Xcode create the to function stubs for us and with that done we can delete our type alias if we open our UI kit file we see the pH picker view controller requires a configuration and that configuration defines what things you are going to allow it to pick in our case we just want images so once the configuration is completed it gets passed on during the instantiation of the picker so these three lines of code here are what we are needed to make our own view I'll just copy them and paste them into the body of our make UI view controller function and return the picker there is a new wrinkle however we need to use the PHP view controller delegate functions and then be able to call these somewhere and this isn't done in the pH picker view controller it's done in that extension to the pH pick up your controller which conforms to the pH picket view controller delegate so as far as the updateui controller function is concerned it doesn't need any code but we still need the empty function and it's required our app builds but it's not yet functional so let's return to our content view so we can present this pH picker when we tap on our button and we can do this as a modal sheet so we need a state variable to do that and I'll call it showing image picker and I'll initialize it as false and then within our get image function we can toggle that value next we can attach a sheet modifier to our button that will present our new picker view when that value is true testing this we see that we get our photos album when the button is tapped unfortunately the cancel button doesn't work and neither does anything happen when I pick an image and if we return to our UI kids view controller we see that functionality is handled in the extension to our view controller it's the delegate function for the pH picker view controller delegate so we need something in our pH pick a view that can handle these delegate functions and this is the job of a coordinator that can coordinate actions between the view and the delegate in PHP curve you will create a class called coordinator inside the struct that conforms to NS object and to the pH picker view controller delegate now it requires one function and that's the didn't finish picking function this creates another problem in that PHP curve you as that no longer conforms to the UI view controller representable we'll let Xcode fix that and we get a new function called make coordinator that returns a coordinator well we have a coordinator class so let's just return an instance of that for the time being and I'm going to move this code down below the update function we also need to do one more thing when we make our view we need to specify who is going to handle the delegate functions well that's the coordinator and the coordinator is part of our context so when we create our instance of the picker view controller in our make function we have to make sure that we assign the coordinator as the delegate and you may recall that the context is an argument of the minke pH picker view controller function and it knows about the coordinator so we can type picker to delegate equals context coordinator we need to know some way of communicating from within our inner class coordinator function to the outer struct or its parent and we can do this by creating a reference to the parent within the class so we'll let the parent be of type PHP curve you but we get two errors our make coordinator function is expecting an argument now for that parent constant and the coordinator is complaining because there's no initializer so we fixed that first initializer problem by creating an initializer in the coordinator where we assign the parent to our PHP curve use version of parent and then in make coordinator we can now pass self which is the parent struct to the coordinator with this in place let's work on our coordinator let's go back to the UI cute example and take a look inside the did finish picking function we have this code here I'm just going to copy it and paste it into our coordinator function and it works except for these two lines of code now the second line doesn't even apply to us because we don't need to change an image views background in fact we don't even have one in our Swift Eli's solution we have an image view that is only displayed if our image is not nil so we'll just remove that next we see we're trying to update an image view with the found image when rather we need to update an image view in our content view and right now our struct doesn't know anything about that this calls for a binding so we need to pass in that image view from our content view as a binding so that when the coordinator function updates it it will refresh that content view so at the top of our struck let's create that binding to an optional image with that in place we can replace this line that is giving us an error our binding is outside of our coordinator class so we need to access the parent and this is an image view and not a UI image so we need to construct the image view using the constructor like this and the final thing we have to do is dismiss the modal sheet and we can do that by using the presentation mode environment variable back in the parent top-level here we can create a presentation mode variable from the environments presentation mode key path and then when we finish to picking we can dismiss the rap value again we're inside a nested function so we need to communicate with the parent so we'll use parent that presentation mode dot wrap value dot dismiss so let's go back to our content view and make sure we pass that image state variable when we present the picker let's test this it works there are a couple of images in the simulator image assets that are broken I've reported this as a feedback and if I use the old image picker it works fine now debug preview isn't working for me in this beta so let me run this in the simulator so I can see any console notifications you see when I pick the flowers for example I'm told that there is no such file or directory [Music] you do see however that I've added a number of my own images here and I can pick these and they get displayed just fine and now on to our last example in this case we want to present an alert view with a text field that when submitted will update the text fields text with whatever we entered while swifty lied does have an alert view but it can't have a text field with it so again we have to rely on a uiviewcontroller representable what makes this a little different from the last example though is that we do not have any delegate functions but the wrinkle here is that a UI alert controller is presented on a view controller and not on a swift UI view so when we create our new swifty is UI view controller representable file we can't make it an alert view we have to make an irregular view controller and then rely on our update UI view controller function to present or dismiss the alert view on top of it so let's get started since this alert view is going to be presented on top of a view controller which itself will be placed on top of our current content view we can use a Z stack that will present the view only when called upon so we'll go back to our content view and create a new state variable called show alert and I'll initialize it as false and this is what we'll use to trigger the presentation or dismissal of our alert view now we can bed our V stack in a Z stack or a Zed stack and at the end of our set stack we'll create a conditional Clause but we will put our alert view and by putting it as the last view of a Z stackers that stack it'll appear on top of any other views behind it when our show alert text is true in our show alert function we can toggle the value when the corresponding button is tapped ok so now we can build our UI view controller representable will create a new file that will call alert with text view will import swift UI and will create a struck with the same name and as before have it conformed to uiviewcontroller representable and we can go through that 3-step dance first we'll let Xcode create the type alias for us and we'll assign it as a uiviewcontroller as I mentioned I'll save the document and then let Xcode generate the to function stubs for our uiviewcontroller we're just going to return a generic view controller let me remove the placeholder in the update function and remove the type alias now as I said earlier we want to update the view whenever the show text alert value has changed so we'll need to know when that value in the view is created this requires a binding for the value that we have in our content view similarly we'll need to pass back any text that is updated and right now in content view that is hard-coded so let's return to content view and add a new state variable that we'll call alert text and give it a default string of Hello question mark question mark and then we can replace that hard-coded string in our text view with this variable back in alert with textview we can then create a binding for that variable now our alert also has a title a message in a placeholder so let's create three properties for these here that will be updated when we create the view we can use let for these properties that they are not updated by our alert text view they are read only once they've been instantiated all three are strings we have all we need now to return to an content view to create our alert text view well replace our comment with the alert text view and we'll pass in our two corresponding bindings and since we're asking for a user name we can pass in name for the title please enter your name for the message and full name for the text placeholder our content view is done but of course no alert will be presented because our alert text views update function is not doing anything yet inside our update view controller we only want to present the alert if show alert text is true so let's create that conditional now let's check our UI kit example to see how we do this in UI kit the first three lines of code here are covered because those are our three constants that we create when we create our view so we'll copy the rest and see what needs to be fixed for the dismiss action instead of self which is the alert view we need to use alert and we can use the constructor of dismiss with the closure to set our show text alert boolean back to false that will close our modal the same will apply here in the second dismiss instance this line here refers to that UI label and it needs to change what we do is assign the string to our alert text binding so it will cause our view to upbeat and replace our textview with that new string now we need to know how to present the alert self refers to the parent view and we are not presenting the view controller on the alert with textview instead we want to present it on the UI view controller that's the argument of this function if we run this now in the simulator however we get an error we're attempting to present a view controller from the view whose view is not in the window hierarchy so what we need to do is wrap that last piece of code inside a dispatch QM in a sink if we run once more the alerts presented there is an error but it doesn't stop it from being presented I can enter my name and I see that the textview gets updated but our alert text doesn't go away well we can fix that last bug by returning to where we present the alert and we'll use the training closure version to set the show text alert to false once our elder it has been submitted that works but I still can't live with this error what we need is to have our alert with text view hold on to an instance of the alert and then release it once we're done and for this we need a coordinator so we've done that before so let's just create one remember we start by creating a coordinator class that conforms to NS object this requires a make coordinator function then we'll just return an instance of the coordinator in the coordinator we need to hold a reference for our UI alert controller that we assign when we are in our update function so I'll create an optional UI alert controller variable that I'll just call alert and back in our update function will ensure that we only present our alert if it is indeed nil not already presenting will use a guard statement to do this our update function has the context as an argument so it's aware of the coordinator which means we have access to check if the alert in there is nil if it isn't we need to return once the alert is created we can assign it that optional variable in our coordinator so context coordinator dot alert equals alert and then finally after dismissing the alert in the closure we set that coordinators alert back to nil and there you have it let's run it and we get no error all three of our uikit views and view controllers are working in Swift view I hope that this has given you a better understanding of how you can add uikit views and view controllers to your own swift UI projects [Music] I have lots of other video is available and in the queue as well so please check out the rest of my channel you can also visit my website to see the apps that I have available on the App Store and visit my github page to see what I have available as public repositories if you like what you've seen give it a thumbs up and subscribe to my channel and ring the bell to get notified when I post new videos I'm most active on Twitter so please follow me there as well to find out what else I'm up to thanks for watching
Info
Channel: Stewart Lynch
Views: 1,421
Rating: undefined out of 5
Keywords: UIViewRepresentable, UIViewControllerRepresentable, PhotosUI, Xcode, SwiftUI, Swift
Id: k4h9i6KVvi8
Channel Id: undefined
Length: 30min 27sec (1827 seconds)
Published: Sun Jul 19 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.