2

How to use UIView in SwiftUI

 1 year ago
source link: https://sarunw.com/posts/uiview-in-swiftui/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

The good thing about SwiftUI is you can gradually adopt it from an existing UIKit application.

In this article, I will show you how to use UIView as a SwiftUI View.

You can easily support sarunw.com by checking out this sponsor.

Artboard%202@2x.png

Sponsor sarunw.com and reach thousands of iOS developers.

Using UIView as SwiftUI View

Before we can use UIView in the SwiftUI world, we need to transform it in a way that SwiftUI can understand.

We need to do two things to make an UIView works inside SwiftUI.

  1. Create a new SwiftUI view that conforms to UIViewRepresentable protocol.
  2. Implement the two required methods makeUIView() and updateUIView().

Before jumping to the implementation detail, let's create a new UIView that we will use throughout the article.

I will call in MyView. It is a simple view with a pink background and a "Hello, UIKit!" label text in the center.

class MyView: UIView {
// 1
private var label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.preferredFont(forTextStyle: .title1)
label.text = "Hello, UIKit!"
label.textAlignment = .center

return label
}()

init() {
super.init(frame: .zero)
// 2
backgroundColor = .systemPink

// 3
addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
label.topAnchor.constraint(equalTo: topAnchor, constant: 20),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20),
])

}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

1 Create a new label and set its text, font, and alignment.
2 Set view background color to pink.
3 Add the label on the center of the view.

This is how it looks.

A view that we will use in SwiftUI.

A view that we will use in SwiftUI.

We got something to work with. Let's see how we can use this view controller in a SwiftUI.

Create UIViewRepresentable

UIViewRepresentable protocol is a SwiftUI view that represents a UIKit view.

As you can see from the declaration, UIViewRepresentable conforms to the View protocol, which makes it usable as a view in the SwiftUI world.

protocol UIViewRepresentable : View where Self.Body == Never

UIViewRepresentable is a bridge between a UIKit view and SwiftUI. There are a few steps that you need to take.

First, I create RepresentedMyView, which conforms to the UIViewRepresentable protocol.

import SwiftUI

struct RepresentedMyView: UIViewRepresentable {

}

The protocol needs to know what kind of UIView that RepresentedMyView is going to represent. We give this information by explicitly defining typealias UIViewType.

In this case, we want our RepresentedMyView to represent MyView.

import SwiftUI

struct RepresentedMyView: UIViewRepresentable {
typealias UIViewType = MyView
}

After we tell the protocol what type of view we will present, we need to get our hands dirty and prepare the view for SwiftUI.

We need to conform to two required methods.

struct RepresentedMyView: UIViewRepresentable {
typealias UIViewType = MyView

func makeUIView(context: Context) -> MyView {
// Return MyView instance.
}

func updateUIView(_ uiView: MyView, context: Context) {
// Updates the state of the specified view with new information from SwiftUI.
}
}

implement makeUIView

The makeUIView method expected us to return an instance of MyView as we specified in typealias UIViewType = MyView.

This is a place where we

  1. Create the view instance and
  2. Configure its initial state

Since our view is very simple, we just create and return it immediately from makeUIView.

struct RepresentedMyView: UIViewRepresentable {
typealias UIViewType = MyView

func makeUIView(context: Context) -> MyView {
let view = MyView()
// Do some configurations here if needed.
return view
}

func updateUIView(_ uiView: MyView, context: Context) {
// Updates the state of the specified view controller with new information from SwiftUI.
}
}

implement updateUIView

The updateUIView method is called when there is an update from SwiftUI. This is a place for us to update our view.

Again, for our simple view, we don't need this. We can leave it blank.

func updateUIView(_ uiView: MyView, context: Context) {
// Updates the state of the specified view controller with new information from SwiftUI.
}

Actually, Swift can infer UIViewType from makeUIView and updateUIView methods.

So technically, we don't need to specify typealias UIViewType = MyView.

struct RepresentedMyView: UIViewRepresentable {
typealias UIViewType = MyView
}

In reality, we don't want to type those two methods manually. So, it is easier to declare typealias UIViewType = MyView and let Xcode generate those two methods for us.

You can do that by clicking the "Fix" button.

Type 'RepresentedMyView' does not conform to protocol 'UIViewRepresentable'

Type 'RepresentedMyView' does not conform to protocol 'UIViewRepresentable'

Or command+click / command+control+click (Based on your setting) and select "Add missing protocol requirements"

Add missing protocol requirements.

Add missing protocol requirements.

How to use UIViewRepresentable

After we create a new view that can represent a UIKit view, we can use it just like a normal SwiftUI view.

In this example, we use RepresentedMyView as a content of a sheet.

struct ContentView: View {
@State var isPresented = false

var body: some View {
Button("MyView") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
RepresentedMyView()
}
}
}
Use RepresentedMyView as a sheet's content.

Use RepresentedMyView as a sheet's content.

As You might notice, the pink background of RepresentedMyView doesn't cover the bottom safe area. We can easily fix that in the SwiftUI way by applying the ignoresSafeArea() modifier.

struct ContentView: View {
@State var isPresented = false

var body: some View {
Button("MyView") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
RepresentedMyView()
.ignoresSafeArea()
}
}
}
We can use a SwiftUI modifier on RepresentedMyView just like a normal SwiftUI view.

We can use a SwiftUI modifier on RepresentedMyView just like a normal SwiftUI view.

As you can see, UIView can represent the whole screen when presenting in SwiftUI.

Here is another example where we use it as a part of a screen.

In this example, we put RepresentedMyView alongside a text view.

struct ContentView: View {
var body: some View {
VStack {
Text("RepresentedMyView")
RepresentedMyView()
.frame(height: 100)
}
}
}
Using RepresentedMyView along side with a SwiftUI Text.

Using RepresentedMyView along side with a SwiftUI Text.

You can easily support sarunw.com by checking out this sponsor.

Artboard%202@2x.png

Sponsor sarunw.com and reach thousands of iOS developers.

Conclusion

The process of using UIView in SwiftUI is almost identical to how we integrated UIViewController with SwiftUI. The only difference is we conform our view with UIViewRepresentable instead of UIViewControllerRepresentable.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK