'Subclassing UIView from Kotlin Native
UIKit is designed to be used through subclasses and overridden methods.
Typically, the drawRect objective-C method of UIView is implemented like this in SWIFT:
import UIKit
import Foundation
class SmileView: UIView {
override func draw(_ rect: CGRect) {
super.draw(rect)
let smile = ":)" as NSString
smile.draw(in: rect, withAttributes: nil)
}
}
Unfortunately, the UIKit import in Kotlin defines these functions as extensions function that cannot be overridden.
Did anybody succeed in subclassing an UIView from Kotlin through a custom cinterop configuration?
Solution 1:[1]
The above answer is awesome, and it served me pretty well until I needed to override updateConstraints() - which has to call super.updateConstraints(). Without that, I was getting runtime errors, and I found no way how to do that call via the Kotlin <-> Swift interop (and now I'm reasonably sure it's really not possible).
So instead, I gave up on trying to subclass the custom UIView in Swift, and only focused on actually instantiating it from Kotlin/Native (so that it is easy to pass it the data it needs):
class CustomView : UIView {
/* Data we need to use from the Kotlin Code */
lazy var kotlinClass: KotlinClass? = nil
... init etc. ...
override func updateConstraints() {
... my stuff ...
super.updateConstraints()
}
override func draw(_ rect: CGRect) {
... call the kotlinClass' methods as you need ...
}
}
And implemented a factory function to instantiate it:
func customViewFactory(kotlinClass: KotlinClass) -> UIView {
return CustomView(kotlinClass: kotlinClass)
}
Then early during the app startup, I pass this factory function to the Kotlin/Native code like this:
KotlinClass.Companion.shared.setCustomViewFactory(factory: customViewFactory(kotlinClass:))
In the Kotlin part of the project (that is actually compiled before the Swift part), it looks like this:
class KotlinClass {
companion object {
/* To be used where I want to instantiate the custom UIView from the Kotlin code. */
lateinit var customViewFactory: (kotlinClass: KotlinClass) -> UIView
/* To be used early during the startup of the app from the Swift code. */
fun setCustomViewFactory(factory: (kotlinClass: KotlinClass) -> UIView) {
customViewFactory = factory
}
}
When I want to instantiate the custom UIView in the Kotlin code, I just call:
val customView = customViewFactory(this)
And then I can work with this customView as I need in the Kotlin part, even though the Kotlin part is compiled first.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jan Holesovsky |
