从 Kotlin Native 子类化 UIView

Gae*_*anZ 5 objective-c ios kotlin swift kotlin-native

UIKit 被设计为通过子类和重写方法来使用。

通常,drawRectUIView 的 Objective-C 方法在 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,Kotlin 中的 UIKit 导入将这些函数定义为无法重写的扩展函数。

有人成功通过自定义配置从 Kotlin 子类化 UIView 吗cinterop

Gae*_*anZ 6

所以我们设法让它发挥作用。

1.在build.gradle.kts中添加cinterop配置任务

kotlin {
    android()
    ios {
        binaries {
            framework {
                baseName = "shared"
            }
        }
        compilations.getByName("main") {
            val uikit by cinterops.creating {
            }

        }
    }
Run Code Online (Sandbox Code Playgroud)

2.添加 `src/nativeinterop/cinterop/uikit.def` 文件。

package = demo.cinterop
language = Objective-C
---

#import <Foundation/Foundation.h>
#import <UIKit/UIView.h>

@protocol UIViewWithOverrides
- (void) drawRect:(CGRect)aRect;
- (void) layoutSubviews;
@end

Run Code Online (Sandbox Code Playgroud)

3.创建自定义UIView类

该类扩展自UIKit的UIView,并实现了之前创建的UIViewWithOverrides Protocol(后缀自动添加)

package demo

import demo.cinterop.UIViewWithOverridesProtocol
import kotlinx.cinterop.*
import platform.CoreGraphics.*
import platform.UIKit.*

@ExportObjCClass
class MyView() : UIView(frame = CGRectMake(.0, .0, .0, .0)), UIViewWithOverridesProtocol {

    override fun layoutSubviews() {
        println("layoutSubviews")
        setNeedsDisplay()
    }

    override fun drawRect(aRect: CValue<CGRect>) {
        val rectAsString = aRect.useContents {
            "" + this.origin.x + ", " + this.origin.y + ", " + (this.origin.x +this.size.width) + ", " + (this.origin.y +this.size.height)
        }
        println("drawRect:: Rect[$rectAsString]")

        val context: CPointer<CGContext>? = UIGraphicsGetCurrentContext()
        CGContextSetLineWidth(context, 2.0)
        val components = cValuesOf(0.0, 0.0, 1.0, 1.0)
        CGContextSetFillColor(context, components)
        val square = CGRectMake(100.0, 100.0, 200.0, 200.0)
        CGContextFillRect(context, square)

    }

}

fun createMyView(): UIView = MyView()

Run Code Online (Sandbox Code Playgroud)

4.从 Swift 使用它

kotlin {
    android()
    ios {
        binaries {
            framework {
                baseName = "shared"
            }
        }
        compilations.getByName("main") {
            val uikit by cinterops.creating {
            }

        }
    }
Run Code Online (Sandbox Code Playgroud)