Top Related Projects
A React-inspired view framework for iOS.
Epoxy is an Android library for building complex screens in a RecyclerView
A data-driven UICollectionView framework for building fast and flexible lists.
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.
Quick Overview
Render is a declarative, functional, and reactive UI framework for building native iOS, iPadOS, and macOS applications. It provides a simple and intuitive API for creating complex user interfaces, with a focus on performance, flexibility, and ease of use.
Pros
- Declarative Approach: Render uses a declarative approach to UI development, which makes it easier to reason about and maintain complex user interfaces.
- Functional and Reactive: The framework is built on functional and reactive programming principles, which can lead to more predictable and testable code.
- Performance: Render is designed to be highly performant, with efficient rendering and update mechanisms.
- Flexibility: The framework is highly customizable and can be integrated with other libraries and frameworks.
Cons
- Learning Curve: Developers who are new to functional and reactive programming may find the learning curve for Render to be steeper than traditional imperative UI frameworks.
- Ecosystem: Render is a relatively new framework, and the ecosystem of third-party libraries and tools may not be as mature as more established UI frameworks.
- Documentation: While the documentation for Render is generally good, some areas may be less comprehensive or up-to-date than users would like.
- Adoption: As a newer framework, Render may not have the same level of adoption and community support as more established UI frameworks.
Code Examples
Here are a few examples of how to use Render to build user interfaces:
// Creating a simple button
let button = Button(
title: "Click me",
action: {
print("Button clicked!")
}
)
// Building a list of items
let items = [
"Item 1",
"Item 2",
"Item 3"
]
let list = List(items) { item in
Text(item)
}
// Handling state and updates
struct CounterState: State {
var count: Int = 0
}
let counter = Counter(CounterState()) { state, dispatch in
VStack {
Text("Count: \(state.count)")
Button(
title: "Increment",
action: {
dispatch(CounterState(count: state.count + 1))
}
)
}
}
Getting Started
To get started with Render, you can follow these steps:
- Install the Render framework using your preferred package manager (e.g., CocoaPods, Carthage, or Swift Package Manager).
- Create a new Xcode project and import the Render framework.
- Define your application's state and create a root component that represents the main user interface.
- Use Render's declarative API to build your UI, handling user interactions and updating the state as needed.
- Customize the appearance and behavior of your UI components by leveraging Render's flexible and extensible design.
- Test and debug your application using Render's built-in debugging tools and integration with other testing frameworks.
For more detailed instructions and documentation, please refer to the Render GitHub repository.
Competitor Comparisons
A React-inspired view framework for iOS.
Pros of ComponentKit
- Backed by Facebook, ensuring long-term support and active development
- Extensive documentation and community resources
- Optimized for performance with large-scale apps
Cons of ComponentKit
- Steeper learning curve due to its complexity
- Limited to Objective-C, which may not be ideal for newer iOS projects
- Requires more boilerplate code compared to Render
Code Comparison
Render:
class MyComponent: Component {
@State var count = 0
func render() -> View {
Button("Count: \(count)") {
count += 1
}
}
}
ComponentKit:
@implementation MyComponent
+ (instancetype)newWithCount:(NSInteger)count {
return [super newWithComponent:
[CKButtonComponent
newWithAction:@selector(incrementCount)
title:[NSString stringWithFormat:@"Count: %ld", (long)count]]];
}
- (void)incrementCount {
[self updateState:^(MyComponentState *state) {
state.count++;
} mode:CKUpdateModeSynchronous];
}
@end
Both frameworks aim to simplify UI development, but Render offers a more modern, Swift-based approach with less boilerplate. ComponentKit provides robust performance optimizations but requires more setup and is limited to Objective-C. Render's syntax is more concise and intuitive for Swift developers, while ComponentKit offers a more structured approach that may be beneficial for larger teams and complex applications.
Epoxy is an Android library for building complex screens in a RecyclerView
Pros of Epoxy
- More mature and widely adopted, with extensive documentation and community support
- Built-in support for diffing and efficient updates, optimizing performance
- Comprehensive set of features, including data binding and view holders
Cons of Epoxy
- Steeper learning curve due to its extensive feature set
- More verbose implementation compared to Render's concise syntax
- Primarily focused on Android development, limiting cross-platform use
Code Comparison
Epoxy:
class HeaderModel(
@EpoxyAttribute var title: String
) : EpoxyModelWithHolder<HeaderHolder>() {
override fun bind(holder: HeaderHolder) {
holder.titleView.text = title
}
}
Render:
class HeaderComponent: Component {
var title: String
func render() -> Node {
Label(title)
}
}
Summary
Epoxy is a robust, feature-rich library for building complex RecyclerViews in Android, offering excellent performance and a wide range of capabilities. Render, on the other hand, provides a more lightweight and concise approach to building user interfaces, with a focus on simplicity and ease of use. While Epoxy excels in Android-specific development, Render offers a more flexible, cross-platform solution. The choice between the two depends on the specific project requirements, target platform, and developer preferences.
A data-driven UICollectionView framework for building fast and flexible lists.
Pros of IGListKit
- Robust and battle-tested in production by Instagram
- Extensive documentation and community support
- Optimized for performance with large datasets
Cons of IGListKit
- Steeper learning curve due to its complexity
- Primarily focused on UICollectionView, less flexible for other UI components
- Requires more boilerplate code for simple use cases
Code Comparison
IGListKit:
let adapter = ListAdapter(updater: ListAdapterUpdater(), viewController: self)
adapter.collectionView = collectionView
adapter.dataSource = self
Render:
let component = MyComponent()
let node = Node(component)
node.render(in: view)
Key Differences
- IGListKit is specifically designed for UICollectionView, while Render is a more general-purpose UI framework
- Render uses a declarative approach, similar to React, while IGListKit follows a more traditional iOS programming model
- IGListKit provides advanced diffing algorithms for efficient updates, whereas Render focuses on simplicity and ease of use
Use Cases
- IGListKit: Ideal for complex, data-driven list interfaces with frequent updates
- Render: Better suited for building custom UI components and simpler view hierarchies
Both libraries aim to improve UI development on iOS, but they take different approaches and cater to different needs within the ecosystem.
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.
Pros of LayoutKit
- More mature and battle-tested, having been used in production by LinkedIn
- Supports a wider range of layout types, including collection views and table views
- Better documentation and examples available
Cons of LayoutKit
- No longer actively maintained (in "attic" status)
- Less flexible for custom layouts compared to Render's component-based approach
- Steeper learning curve due to its more complex API
Code Comparison
LayoutKit:
let layout = InsetLayout(
insets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10),
sublayout: LabelLayout(text: "Hello, World!")
)
Render:
class HelloWorldComponent: Component {
override func render() -> NodeType {
return Label().text("Hello, World!").padding(10)
}
}
Summary
LayoutKit offers a more comprehensive solution for complex layouts, especially for large-scale applications. However, its development has stalled, and it may not be suitable for new projects. Render, on the other hand, provides a more modern, component-based approach that aligns well with current UI development trends, albeit with a potentially smaller feature set.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Render
CoreRender is a SwiftUI inspired API for UIKit (that is compatible with iOS 10+ and ObjC).
Introduction
- Declarative: CoreRender uses a declarative API to define UI components. You simply describe the layout for your UI based on a set of inputs and the framework takes care of the rest (diff and reconciliation from virtual view hierarchy to the actual one under the hood).
- Flexbox layout: CoreRender includes the robust and battle-tested Facebook's Yoga as default layout engine.
- Fine-grained recycling: Any component such as a text or image can be recycled and reused anywhere in the UI.
TL;DR
Let's build the classic Counter-Example.
The DSL to define the vdom representation is similiar to SwiftUI.
func makeCounterBodyFragment(context: Context, coordinator: CounterCoordinator) -> OpaqueNodeBuilder {
Component<CounterCoordinator>(context: context) { context, coordinator in
VStackNode {
LabelNode(text: "\(coordinator.count)")
.textColor(.darkText)
.background(.secondarySystemBackground)
.width(Const.size + 8 * CGFloat(coordinator.count))
.height(Const.size)
.margin(Const.margin)
.cornerRadius(Const.cornerRadius)
HStackNode {
ButtonNode()
.text("TAP HERE TO INCREASE COUNT")
.setTarget(coordinator, action: #selector(CounterCoordinator.increase), for: .touchUpInside)
.background(.systemTeal)
.padding(Const.margin * 2)
.cornerRadius(Const.cornerRadius)
}
}
.alignItems(.center)
.matchHostingViewWidth(withMargin: 0)
}
}
Label
and Button
are just specialized versions of the Node<V: UIView>
pure function.
That means you could wrap any UIView subclass in a vdom node. e.g.
Node(UIScrollView.self) {
Node(UILabel.self).withLayoutSpec { spec in
// This is where you can have all sort of custom view configuration.
}
Node(UISwitch.self)
}
The withLayoutSpec
modifier allows to specify a custom configuration closure for your view.
Coordinators
are the only non-transient objects in CoreRender. They yeld the view internal state and
they are able to manually access to the concrete view hierarchy (if one desires to do so).
By calling setNeedsReconcile
the vdom is being recomputed and reconciled against the concrete view hiearchy.
class CounterCoordinator: Coordinator{
var count: UInt = 0
func incrementCounter() {
self.count += 1 // Update the state.
setNeedsReconcile() // Trigger the reconciliation algorithm on the view hiearchy associated to this coordinator.
}
}
Finally, Components
are yet again transient value types that bind together a body fragment with a
given coordinator.
class CounterViewCoordinator: UIViewController {
var hostingView: HostingView!
let context = Context()
override func loadView() {
hostingView = HostingView(context: context, with: [.useSafeAreaInsets]) { context in
makeCounterBodyFragment(context: context, coordinator: coordinator)
}
self.view = hostingView
}
override func viewDidLayoutSubviews() {
hostingView.setNeedsLayout()
}
}
Components can be nested in the node hierarchy.
func makeFragment(context: Context) {
Component<FooCoordinator>(context: context) { context, coordinator in
VStackNode {
LabelNode(text: "Foo")
Component<BarCoordinator>(context: context) { context, coordinator in
HStackNode {
LabelNode(text: "Bar")
LabelNode(text: "Baz")
}
}
}
}
}
Use it with SwiftUI
Render nodes can be nested inside SwiftUI bodies by using CoreRenderBridgeView
:
struct ContentView: View {
var body: some View {
VStack {
Text("Hello From SwiftUI")
CoreRenderBridgeView { context in
VStackNode {
LabelNode(text: "Hello")
LabelNode(text: "From")
LabelNode(text: "CoreRender")
}
.alignItems(.center)
.background(UIColor.systemGroupedBackground)
.matchHostingViewWidth(withMargin: 0)
}
Text("Back to SwiftUI")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Credits:
Layout engine:
Top Related Projects
A React-inspired view framework for iOS.
Epoxy is an Android library for building complex screens in a RecyclerView
A data-driven UICollectionView framework for building fast and flexible lists.
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot