UIButtonをdeclarativeに扱う
Objective-CXcodeiOSVue.jsSwift
2019年03月31日
vueとかanglureとか触ってるとSwiftでボタン定義するのすごくだるいなと思う。(mac book airなのでIBは触りたくない)
<button ng-click="ctrl.onClick">anglure</button>
<button v-on:click="say('what')"> vue </button>
だからButtonクラスを作ってちょっとだけ楽してみた。
final class ViewController: UIViewController {
private lazy var button = Button(
title: "click",
backgroundColor: .blue,
parent: view,
onClick: onClickButton
)
private var onClickButton = {
print("tap")
}
}
ちなみにself参照するときはweakつけないとなーくらいに思ってたんでずけど、
private var onClickButton = { [weak self] in
self?.hogehoge()
}
関数を渡してあげると、buttonが解放されなかった。なんででしょうか・・
final class ViewController: UIViewController {
private lazy var button = Button(
title: "click",
backgroundColor: .blue,
parent: view,
onClick: tapButton
)
private func tapButton() {
print("tap")
}
}
ソースはこれです
final class Button: UIButton {
convenience init(
title: String = "",
color: UIColor = .darkGray,
backgroundColor: UIColor = .clear,
parent: UIView? = nil,
onClick: (() -> Swift.Void)? = nil
) {
self.init(frame: .zero)
addTarget(self, action: #selector(actionClick), for: .touchUpInside)
setTitle(title, for: .normal)
setTitleColor(color, for: .normal)
self.backgroundColor = backgroundColor
clickHandler = onClick
parent?.addSubview(self)
}
private var clickHandler: (() -> Swift.Void)?
@objc private func actionClick() {
clickHandler?()
}
}
Swiftでもこうやってかけるようにしてみようかな・・
private lazy var label = Label(
textColor: .darkGray,
parent: view,
bind: store.state.text
)
昔ちょこっと試してた初期化方法(おまけ)
lazyで初期化
基本的にはこれで初期化している。Extensionを使ってないから普通にSnipetにしてどこでも使える。
final class ViewController: UIViewController {
private lazy var button: UIButton = {
let b = UIButton()
b.setTitle("button", for: .normal)
b.addTarget(self, action: #selector(actionTap), for: .touchUpInside)
...
return b
}()
@objc private func actionTap() {
print("button touch up inside")
}
}
メソッドチェーンで初期化
メソッドチェーンでかけるExtensionを作ってKotlinのスコープ関数のように初期化してみたり
final class ViewController: UIViewController {
private lazy var button = UIButton().apply { $0
.setTitle("button", for: .normal)
.addTarget(self, action: #selector(actionTap), for: .touchUpInside)
...
}
@objc private func actionTap() {
print("button touch up inside")
}
}
AddTargetのみ省略
RxSwiftのbutton.rx.tap
が便利だったので
NotificationCenterやocjcの黒魔術を使ってaddTargetのみ省略したり
final class ViewController: UIViewController {
private var button = UIButton()
private func setUpButton() {
button.setTitle("button", for: .normal)
button.onTap = {
print("button touch up inside")
}
}
}