Easily use UIKit views in your SwiftUI applications. Create Xcode Previews for UIView elements

Overview

SwiftUIKitView

Swift Version Dependency frameworks Twitter

Easily use UIKit views in SwiftUI.

  • Convert UIView to SwiftUI View
  • Create Xcode Previews from UIView elements
  • SwiftUI functional updating UIView properties using a protocol with Associated Types.

You can read more about Getting started with UIKit in SwiftUI and visa versa.

Examples

Using a UIKit view directly in SwiftUI:

<- Use key paths for updates. .set(\.backgroundColor, to: UIColor(named: "swiftlee_orange")) .fixedSize() .navigationTitle("Use UIKit in SwiftUI") } } } ">
import SwiftUI
import SwiftUIKitView

struct SwiftUIwithUIKitView: View {
    var body: some View {
        NavigationView {
            UILabel() // <- This can be any `UIKit` view.
                .swiftUIView(layout: .intrinsic) // <- This is returning a SwiftUI `View`.
                .set(\.text, to: "Hello, UIKit!") // <- Use key paths for updates.
                .set(\.backgroundColor, to: UIColor(named: "swiftlee_orange"))
                .fixedSize()
                .navigationTitle("Use UIKit in SwiftUI")
        }
    }
}

Creating a preview provider for a UIView:

<- Use key paths for updates. .fixedSize() // <- Make sure the size is set .previewLayout(.sizeThatFits) .previewDisplayName("UILabel Preview Example") } } ">
import SwiftUI
import SwiftUIKitView

struct UILabelExample_Preview: PreviewProvider {
    static var previews: some View {
        UILabel() // <- This is a `UIKit` view.
            .swiftUIView(layout: .intrinsic) // <- This is a SwiftUI `View`.
            .set(\.text, to: "Hello, UIKit!") // <- Use key paths for updates.
            .fixedSize() // <- Make sure the size is set
            .previewLayout(.sizeThatFits)
            .previewDisplayName("UILabel Preview Example")
    }
}

Which results in the following preview:

KeyPath updating

This framework also comes with a KeyPathReferenceWritable protocol that allows to update objects using functions and writable KeyPath references:

/// Defines a type that is configurable using reference writeable keypaths.
public protocol KeyPathReferenceWritable {
    associatedtype T
    associatedtype U
    
    func set<Value>(_ keyPath: ReferenceWritableKeyPath
   Value>, 
   to 
   value: 
   Value) 
   -> U
}


   public 
   extension 
   KeyPathReferenceWritable {
    
   func 
   set<
   Value>(
   _ 
   keyPath: ReferenceWritableKeyPath<
   Self, 
   Value>, 
   to 
   value: 
   Value) 
   -> 
   Self {
        
   self[
   keyPath: keyPath] 
   = value
        
   return 
   self
    }
}


   /// Add inheritance for NSObject types to make the methods accessible for many default types.

   
   extension 
   NSObject: 
   KeyPathReferenceWritable { }
  

This can be used as follows:

UILabel()
    .set(\.text, to: "Example")

And allows to easily build up SwiftUI style view configurations to keep the same readability when working in SwiftUI.

Installation

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but this SDK does support its use on supported platforms.

Once you have your Swift package set up, adding the SDK as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/AvdLee/SwiftUIKitView.git", .upToNextMajor(from: "1.0.0"))
]

Communication

  • If you found a bug, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, submit a pull request.

License

SwiftUIKitView is available under the MIT license, and uses source code from open source projects. See the LICENSE file for more info.

Author

This project is originally created by Antoine van der Lee. I'm open for contributions of any kind to make this project even better.

Comments
  • Question on UIActivityIndicatorView compatibility

    Question on UIActivityIndicatorView compatibility

    Hi, I have tried the library it is very perfectly if I am adding an UILabel or UIView. But now I am trying to add UIActivityIndicatorView, seems it doesn't work. Is this syntax below correct ?. I tried this but the view is not showing anything, but once I try with UILabel or UIView, it works fine.

    UIActivityIndicatorView(style: .large)
                    .swiftUIView(layout: .fixed(size: CGSize(width: 100, height: 100)))
                    .set(\.color, to: UIColor.blue)
                    .set(\.isHidden, to: false)
                    .fixedSize()
    

    second question, how did I trigger a function that preserved from one of the subclass of UIView ? Let say this activity indicator has an open function called as startAnimating(). however I can't using the declarative syntax in above code, is it expected to only set a value but can't call any derived method ?

    Thank you before, @AvdLee

    opened by abadikaka 2
  • Action isn't being called?

    Action isn't being called?

    public struct ContentView: View {
            var body: some View {
                    return AnyView(
                            ViewController().view
                                    .swiftUIView(layout: .intrinsic)
                    )
            }
    }
    
    class ViewController: UIViewController {
    	
    	var scrollView = UIScrollView()
    	let contentView = UIView()
    	var pullControl = UIRefreshControl()
    	
    	override func viewDidLoad() {
    		super.viewDidLoad()
    		
    		setupScrollView()
    		setupViews()
    	}
    	
    	@objc func handleRefreshControl() {
    		// Update your content…
    		print("hi")
    		// Dismiss the refresh control.
    		DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    			self.scrollView.refreshControl?.endRefreshing()
    		}
    	}
    	
    	func setupScrollView(){
    		scrollView.translatesAutoresizingMaskIntoConstraints = false
    		contentView.translatesAutoresizingMaskIntoConstraints = false
    		
    		view.addSubview(scrollView)
    		scrollView.addSubview(contentView)
    		
    		scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    		scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    		scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    		scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    		scrollView.backgroundColor = UIColor.red
    		
    		scrollView.refreshControl = pullControl
    		
    		
    		scrollView.refreshControl?.addTarget(self, action:
    												#selector(handleRefreshControl),
    											 for: .valueChanged)
    		
    		
    		contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
    		contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
    		contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    		contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    	}
    	
    	func setupViews(){
    		child.view.sizeToFit()
    		child.view.translatesAutoresizingMaskIntoConstraints = false
    		contentView.addSubview(child.view)
    		child.view.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
    		child.view.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
    		child.view.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
    		child.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    	}
    	
    	let child: UIHostingController = UIHostingController(rootView: TestView())
    }
    
    public struct TestView : View {
    	public var body: some View {
    		VStack {
    			Group {
    				Text("Test1")
    				Text("Test2")
    				Text("Test3")
    				Text("Test4")
    				Text("Test5")
    				Text("Test6")
    				Text("Test7")
    				Text("Test8")
    				Text("Test9")
    				Text("Test10")
    			}
    		}
    	}
    }
    
    

    When I swipe to refresh, refreshData isn't being called. The refresh animation plays endlessly. However, my code works when it isn't embedded in a SwiftUI view. Is this issue fixable?

    opened by baraql 1
  • Update not working?

    Update not working?

    struct ContentView: View {
        @State var counter = 0
        
        var body: some View {
            VStack {
                
                Text("Hello no \(counter) from SwiftUI")
                    .padding()
                
                UILabel() // <- This can be any `UIKit` view.
                    .swiftUIView(layout: .intrinsic) // <- This is returning a SwiftUI `View`.
                    .set(\.text, to: "Hello no \(self.counter) from UIKit") // <- Use key paths for updates.
                    .fixedSize()
            }
            .onAppear {
                if counter == 0 {
                    schedule()
                }
            }
        }
        
        func schedule() {
            counter += 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.schedule()
            }
        }
    }
    

    simulator_screenshot_581B71A7-9A1F-45C6-8F09-2E1AB04392C5

    I expected the UILabel to be updated and behave like my SwiftUI Text-view, but instead it is showing just 0. Also, recreating the UILabel every time the view hierarchy is declared is not a good idea as it may happen many many times. I think this is a fundamental issue with the approach in this library. I find this approach better and easier

    import SwiftUI
    import UIKit
    
    struct UIViewMaker<ViewType: UIView>: UIViewRepresentable {
        
        typealias UIViewType = ViewType
        
        var make: () -> ViewType = ViewType.init
        var update: (ViewType) -> ()
        
        func makeUIView(context: Context) -> ViewType {
            return make()
        }
        
        func updateUIView(_ uiView: ViewType, context: Context) {
            update(uiView)
        }
    }
    
    struct ContentView: View {
        @State var counter = 0
        
        var body: some View {
            VStack {
                
                Text("Hello no \(counter) from SwiftUI")
                    .padding()
                
                
                UIViewMaker<UILabel> {
                    $0.text = "Hello no \(self.counter) from UIKit"
                }
                .fixedSize()
                
            }
            .onAppear {
                if counter == 0 {
                    schedule()
                }
            }
        }
        
        func schedule() {
            counter += 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.schedule()
            }
        }
    
    }
    
    opened by hfossli 1
  • Production ready code for UIKit in SwiftUI

    Production ready code for UIKit in SwiftUI

    I initially built SwiftUIKitView to create previews for UIKit views quickly. Though, many started using this framework in production code, for which it was not optimized.

    Code changes in this PR do optimize for production, making it easier to use UIKit views in production apps.

    Fixes #2 Fixes #3

    opened by AvdLee 0
  • `UILabel` Preview Example not working

    `UILabel` Preview Example not working

    UILabel Preview Example in project SwiftUIKitExample.xcodeproj does not work.

            UILabel() // <- This is a `UIKit` view.
                .swiftUIView(layout: .intrinsic) // <- This is a SwiftUI `View`.
                .set(\.text, to: "Hello, UIKit!") // <- Use key paths for updates.
                .fixedSize() // <- Make sure the size is set
                .previewLayout(.sizeThatFits)
                .previewDisplayName("UILabel Preview Example")
        }
    

    Expected to see the text "Hello, UIKit!" but that text is not visible in the preview :(

    https://user-images.githubusercontent.com/4176826/193900800-b6b01da1-5898-43b8-a3a8-2606e380f04c.mov

    Tested with Xcode 14.0.1 and iPhone 13 (iOS 16) simulator

    opened by MarcoEidinger 1
  • Added dynamicMemberLookup support

    Added dynamicMemberLookup support

    This PR leverages dynamicMemberLookup to allow setting properties in the same style as SwiftUI.

    Unfortunately DML cannot be implemented by a protocol so the implementation needs to be duplicated between the conforming types (UIViewContainer and ModifiedUIViewContainer)

    opened by jayrhynas 1
Releases(2.0.0)
  • 2.0.0(Jul 23, 2022)

    I initially built SwiftUIKitView to create previews for UIKit views quickly. Though, many started using this framework in production code, for which it was not optimized.

    I'm happy to announce that this major update adds support to the use of the framework in production apps.

    Using a UIKit view directly in SwiftUI for production code requires you to use:

    UIViewContainer(<YOUR UIKit View>, layout: <YOUR LAYOUT PREFERENCE>)
    

    Performance in Previews is less important, it's being redrawn either way. Therefore, you can use the more convenient swiftUIView() modifier:

    UILabel() // <- This is a `UIKit` view.
        .swiftUIView(layout: .intrinsic) // <- This is returning a SwiftUI `View`.
    
    Source code(tar.gz)
    Source code(zip)
  • 1.0.3(Jul 20, 2021)

  • 1.0.2(Jan 7, 2021)

  • 1.0.1(Jan 6, 2021)

  • 1.0.0(Jan 4, 2021)

Owner
Antoine van der Lee
iOS Developer @WeTransfer — Owner of SwiftLee
Antoine van der Lee
Easy-to-use HStack that snaps to elements on scroll.

SnapToScroll Drop-in SwiftUI-based container view for horizontal snapping. example-video.mp4 Getting Started Using SnapToScroll is straightforward. Th

null 206 Jan 7, 2023
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022
Oovium's AetherView and other basic UI elements necessary for embedding Oovium in other apps

Oovium's AetherView and other basic UI elements necessary for embedding Oovium in other apps

Joe Charlier 0 Aug 24, 2022
Easily add drop shadows, borders, and round corners to a UIView.

Easily add drop shadows, borders, rounded corners to a UIView. Installation CocoaPods Add the follwing to your Podfile: pod 'Shades' Usage Storyboard

Aaron Sutton 14 Jun 20, 2020
Create SwiftUI Views with any data

Create SwiftUI Views with any data

Zach Eriksen 20 Jun 27, 2022
Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views

StatusProvider Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views CocoaPods Podfile pod 'StatusProvider'

Mario Hahn 887 Dec 22, 2022
A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI.

A set of UIKit helpers that simplify the usage of UIKit view's and controller's in SwiftUI. Many of these helpers are useful even in a pure UIKit project.

SwiftUI+ 6 Oct 28, 2022
Create descriptive UIKit screens, faster!

Columbina's DeclarativeUIKit Create descriptive UIKit screens, faster! Get rid of constraints manipulation and use declarative language to create your

Columbina 2 Dec 12, 2021
Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle.

Twinkle ✨ Twinkle is a Swift and easy way to make any UIView in your iOS or tvOS app twinkle. This library creates several CAEmitterLayers and animate

patrick piemonte 600 Nov 24, 2022
Create macOS apps with Swift packages instead of Xcode projects

Swift Bundler A Swift Package Manager wrapper that allows the creation of MacOS apps with Swift packages instead of Xcode projects. My motivation is t

null 182 Dec 25, 2022
Zeplin component preview for your SwiftUI views

A Zeplin component preview for your SwiftUI views. You can use Zeplin components instead of real views within your app until you implement them.

Danis Tazetdinov 4 Sep 1, 2022
Simple battery shaped UIView

BatteryView Simple battery shaped UIView. Usage let batteryView = BatteryView(frame: smallRect) batteryView.level = 42 // anywhere in 0...100 batteryV

Yonat Sharon 50 Sep 19, 2022
Elissa displays a notification on top of a UITabBarItem or any UIView anchor view to reveal additional information.

Elissa Attach a local notification to any UIView to reveal additional user guidance. Usage Example Per default, Elissa will try to align to the center

null 169 Aug 14, 2022
UIView and CGRect extension that adds properties to manipulate them efficiently

Geometry Geometry is a UIView and CGRect extension that lets you work with view and rect geometry easier. It adds the following properties to UIView:

Tuomas Artman 92 Sep 7, 2022
An iOS Library that makes shadows management easy on UIView.

ShadowView is an iOS Shadow library that makes view's shadow implementation easy and sweet ?? ?? . Add simple shadows to add a gaussian blurred projec

Pierre 404 Dec 8, 2022
High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton, Promise and more.

SwiftyUI High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton and more. Features SwiftyView GPU rendering Image and Color

Haoking 336 Nov 26, 2022
Custom Beautiful UIView For Handling IDs in iOS

IDView Custom Beautiful UIView For Handling IDs in iOS Setup Set the placeholder images for the front and back faces. override func viewDidLoad()

Omar Labib 6 Aug 21, 2021
A framework which helps you attach observers to `UIView`s to get updates on its frame changes

FrameObserver is a framework that lets you attach observers to any UIView subclass and get notified when its size changes. It doesn't use any Method S

null 11 Jul 25, 2022
A swift PropertyWrapper to provide automatic NSView/UIView invalidation when the properties value changes.

A swift PropertyWrapper to provide automatic NSView/UIView invalidation when the properties value changes. It duplicates the @Invalidating propertyWrapper for build targets prior to macOS 12 and iOS 15.

Darren Ford 8 Oct 15, 2021