A Swift package that enables seamless integration between UIKit and SwiftUI components.
HybridKit is a powerful framework that bridges UIKit and SwiftUI, allowing developers to embed SwiftUI views within UIKit components. This enables gradual migration from UIKit to SwiftUI or the use of SwiftUI's declarative syntax within existing UIKit-based applications.
The framework provides hybrid versions of common UIKit components:
- View Controllers
- Table View Cells
- Table View Header/Footer Views
HybridControllerHybridControllerWith
HybridTableViewCellHybridTableViewCellWithHybridTableHeaderFooterViewHybridTableHeaderFooterViewWith
- Easy Integration: Seamlessly embed SwiftUI views in UIKit components
- Observable Object Support: Full support for SwiftUI's
@ObservableObjectand data binding - Generic Configuration: Type-safe configuration for table view cells and header/footer views
- iOS Compatibility: Works on iOS platforms (excludes macOS)
- Automatic Layout: Handles Auto Layout constraints automatically
Create a hybrid view controller by subclassing HybridController:
import HybridKit
import SwiftUI
class MyViewController: HybridController {
override var body: any View {
VStack {
Text("Hello, HybridKit!")
Button("Tap me") {
// Handle button tap
}
}
.padding()
}
}For data-driven UIs, use HybridControllerWith with an ObservableObject:
class MyViewModel: ObservableObject {
@Published var text: String = "Hello"
@Published var counter: Int = 0
}
class DataViewController: HybridControllerWith<MyViewModel> {
override var body: any View {
VStack {
Text(observedObject.text)
Text("Count: \(observedObject.counter)")
Button("Increment") {
observedObject.counter += 1
}
}
.padding()
}
}
// Usage
let viewModel = MyViewModel()
let viewController = DataViewController(observedObject: viewModel)Create custom table view cells with SwiftUI content:
class CustomTableViewCell: HybridTableViewCellWith<String> {
override func body(with configure: String) -> any View {
HStack {
Image(systemName: "star.fill")
.foregroundColor(.yellow)
Text(configure)
.font(.headline)
Spacer()
}
.padding()
}
}
// In your table view data source
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomTableViewCell
cell.configure(with: "Item \(indexPath.row)")
return cell
}Create custom header and footer views:
class SectionHeaderView: HybridTableHeaderFooterViewWith<String> {
override func body(with configure: String) -> any View {
HStack {
Text(configure)
.font(.title2)
.fontWeight(.bold)
Spacer()
}
.padding()
.background(Color.gray.opacity(0.1))
}
}
// Usage in table view delegate
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! SectionHeaderView
headerView.configure(with: "Section \(section)")
return headerView
}HybridKit
├── HybridController (Base View Controller)
├── HybridControllerWith<Object> (View Controller with Observable Object)
├── HybridTableViewCell (Base Table Cell)
├── HybridTableViewCellWith<CellConfigure> (Configurable Table Cell)
├── HybridTableHeaderFooterView (Base Header/Footer)
└── HybridTableHeaderFooterViewWith<HeaderFooterConfigurable> (Configurable Header/Footer)
- Inheritance-based: Extend hybrid classes and override the
bodymethod - Type Safety: Generic types ensure compile-time safety for configurations
- Memory Management: Automatic cleanup in
prepareForReuse()methods - Constraint Handling: Automatic Auto Layout setup and cleanup
Hybrid view controllers work seamlessly with UIKit navigation:
class HomeViewController: HybridControllerWith<HomeViewModel> {
override func viewDidLoad() {
super.viewDidLoad()
// Set up Combine subscriptions for UIKit integration
observedObject.$presentError
.sink { [weak self] error in
if let error = error {
self?.showAlert(for: error)
}
}
.store(in: &cancellables)
}
override var body: any View {
List {
Section("Navigation") {
Button("Push New View") {
let newVC = DetailViewController()
navigationController?.pushViewController(newVC, animated: true)
}
}
Section("Input") {
TextField("Enter text", text: $observedObject.inputText)
}
}
}
private func showAlert(for error: Error) {
let alert = UIAlertController(title: "Error",
message: error.localizedDescription,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}Create sophisticated table view cells with SwiftUI:
struct ItemData {
let title: String
let subtitle: String
let imageName: String
let isSelected: Bool
}
class ComplexTableViewCell: HybridTableViewCellWith<ItemData> {
override func body(with configure: ItemData) -> any View {
HStack(spacing: 12) {
Image(systemName: configure.imageName)
.frame(width: 24, height: 24)
.foregroundColor(configure.isSelected ? .blue : .gray)
VStack(alignment: .leading, spacing: 4) {
Text(configure.title)
.font(.headline)
.foregroundColor(.primary)
Text(configure.subtitle)
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
if configure.isSelected {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.blue)
}
}
.padding(.vertical, 8)
.padding(.horizontal, 16)
}
}- Hybrid components automatically handle view cleanup in
prepareForReuse() - Store Combine subscriptions in view controllers for proper lifecycle management
- SwiftUI views are embedded using
UIHostingController - Consider view complexity for table view cells to maintain smooth scrolling
- Use
@ObservableObjectfor shared state between UIKit and SwiftUI - Leverage Combine for reactive programming patterns
- Hybrid components can be tested using standard UIKit testing approaches
- SwiftUI content can be tested independently
- iOS: ✅ Supported
- macOS: ❌ Not supported (UIKit dependency)
- watchOS: ❌ Not supported (UIKit dependency)
- tvOS: ✅ Should work (UIKit available)
- Replace
UIViewControllerwithHybridController - Move UI logic to the
bodyproperty using SwiftUI syntax - Gradually convert complex views to SwiftUI
- Use hybrid components when UIKit integration is needed
- Wrap SwiftUI views in hybrid containers for UIKit compatibility
- Maintain SwiftUI patterns while gaining UIKit capabilities
- iOS 13.0+
- Swift 5.0+
- Xcode 11.0+
Add HybridKit to your project using Swift Package Manager:
dependencies: [
.package(url: "https://github.com/your-repo/HybridKit.git", from: "1.0.0")
]