【SwiftUI 】iOS14 での変更点への対応( keyboard と ObservedObject )

2021年1月27日

自分が今のところ対応した

  • keyboard が出た際の自動 view 位置上下させない方法
  • ObservedObject の仕様変更?

についてです。

keyboard 位置の自動調整

今まではキーボードが出ても画面の位置は変わらないので TextField がキーボードで隠れない様に view の位置を上げ下げするような実装をする必要がありましたが iOS14 からは自動で上下するようになりました。しかし逆に view に動いて欲しく無い場合もあると思います。

例えば適当に以下の様な VIew があった時 iOS14 では kyebord が出た際に自動で高さ調節されるので以下の画像の様に周りの Rectangle が縮みます。

struct ContentView: View {
    @State var text = ""
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Rectangle()
                    .fill(Color.red)
                
                TextField("プレースホルダー", text: $text)
                .padding()
                
                Rectangle()
                    .fill(Color.green)
                
                Rectangle()
                
                Rectangle()
                    .fill(Color.blue)
                
            }
            .frame(width: geometry.size.width, height: geometry.size.height)
        }
    }
}

この様に自動の高さ調節をして欲しくない場合は以下の様に ignoresSafeArea(.keyboard) を追加します。

struct ContentView: View {
    @State var text = ""
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Rectangle()
                    .fill(Color.red)
                
                TextField("プレースホルダー", text: $text)
                .padding()
                
                Rectangle()
                    .fill(Color.green)
                
                Rectangle()
                
                Rectangle()
                    .fill(Color.blue)
                
            }
            .ignoresSafeArea(.keyboard)
            .frame(width: geometry.size.width, height: geometry.size.height)
        }
    }
}

これだけでこの挙動を消すことができます。基本的にはこの自動調節は便利ですが逆に無効にしたい場合この様な方法が可能です。

ObservedObject の仕様変更?

iOS13 では以下の様に ObservedObject を実装したクラスのインスタンスを他のクラスに渡す時に受け取った側のクラスでは @ObservedObject のアノテーションをつけなくても受け取った側で使えていたのですが iOS14 では受け取った側でもアノテーションが必要な様です。  @State で宣言していたインスタンスを渡す場合は受け取り側では @Binding をつけていましたが、それと同じ様に @ObservedObject で宣言していたものに関しては受け取り側でも @ObservedObject が必要な様です。

自分の場合は以下の様な UIViewRepresentable を使った UITextView に ObservedObject を実装したインスタンス(tmpTextVM)を渡していたのですが、それの変化に反応してくれないと言う問題があったのでこれに気づきました。

struct CustomTextView: UIViewRepresentable {
    var tmpTextVM: TmpTextViewModel
    
    func makeUIView(context: UIViewRepresentableContext<CustomTextView>) -> UITextView {
        let textView = UITextView()
        textView.backgroundColor = UIColor.clear
        textView.isScrollEnabled = false
        textView.text = "test"
        textView.font = UIFont(name: "ArialMT", size: 20)
        return textView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.textColor = tmpTextVM.color
        
    }
}
struct ContentView: View {
    
    @ObservedObject var tmpTextVM: TmpTextViewModel
   
        var body: some View {

            VStack {
                
                Button(action: {
                    tmpTextVM.changeColor(UIColor.red)
                }){
                    Image(systemName:"eyedropper.full")
                }
                
                CustomTextView(tmpTextVM: tmpTextVM)
                    .foregroundColor(Color(tmpTextVM.color))
                    .frame(width:300, height: 300, alignment: .topLeading)
                    .border(Color.red, width: 1)
                    
            }
    }
}

CustomTextView の中で @ObservedObject var tmpTextVM: TmpTextViewModel の様にアノテーションをつけるとこちらは動作しました。

この辺り細かい仕様ははっきり把握していないので間違い等あればご指摘お願いいたします。

広告

SwiftUI 徹底入門 [ 金田 浩明 ]

価格:3,278円
(2020/11/18 22:49時点)
感想(0件)

詳細!SwiftUI iPhoneアプリ開発入門ノート iOS 13 Xcode 11対応【電子書籍】[ 大重美幸 ]

価格:2,970円
(2020/11/18 22:52時点)
感想(0件)

swift

Posted by tsukasa