[iOS14] ScrollViewReader를 사용하여 간단한 채팅 구현

지금까지 채팅 구현의 어려움과 iOS14의 접근 방식



UIKit에서 채팅 앱을 구현할 때 UITableView를 사용하는 경우가 많다고 생각합니다.
LINE과 같은 채팅의 경우는 특히 高さの計算 , 一番下へスクロール 의 구현이 어렵네요.
지금까지의 경험에 의해, 구현도 복잡해져 버그도 많기도 했습니다.
iOS14 가 되고 나서는, SwiftUI의 ScrollViewReader 가 나오고, 대개 채팅의 구현이 편해졌습니다.

환경


  • Xcode12.2
  • iOS14.2(SwiftUI2)

  • ScrollViewReader란?



    프로그래밍 방식으로 스크롤할 수 있습니다.
    ScrollViewReader - Apple 공식 문서
    
    ScrollView {
      ScrollViewReader { (proxy: ScrollViewProxy) in
        ...
      }
    }
    

    ScrollViewReader의 클로저에서 ScrollViewProxy에 액세스 할 수 있습니다. 이것을 저장하고,scrollTo 에서 프로그래밍 방식으로 스크롤합니다.
    
    func scrollTo<ID>(_ id: ID, anchor: UnitPoint? = nil) where ID : Hashable
    

    간단한 채팅으로 사용해 보았습니다.


    struct ContentView: View {
    
        @ObservedObject private var viewModel: ViewModel = .init()
    
        @State var text: String = ""
        @State var value: ScrollViewProxy?
    
        var body: some View {
            VStack {            
                ScrollView {
                    ScrollViewReader { value in
                        LazyVStack(alignment: .center, spacing: 16) {
                            //チャットの表示
                            ForEach.init(self.viewModel.messages, id: \.id) { message in
                                ChatView.init(message: message)
                            }
                        }.onAppear {
                            self.value = value //ScrollViewProxyを保存する
                            self.value?.scrollTo(self.viewModel.messages.count, anchor: .bottom) //初めに表示された時に一番下までスクロールする
                        }.animation(.easeInOut)
                    }
                }
    
                //テキスト入力欄
                VStack {
                    ...
                }.background(Color(white: 0.95))
            }
        }
    }
    
    extension ContentView {
    
        //送信ボタンを押した時
        func sendText() {
            viewModel.send(text: text)
            text = ""
            guard let message = viewModel.messages.last else { return }
            debugPrint(message)
            //わずかにタイミングをずらさないと、スクロールできない
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
                withAnimation {
                    //一番下にアニメーションする
                    self.value?.scrollTo(message.id, anchor: .bottom)
                }
    
            })
        }
    
    }
    

    스쿠쇼



    소스 코드



    참고



    htps : //로 ゔぇぺぺr. 아 ぇ. 코 m / 도쿠 멘 타치 온 / 슈 f 타이 / sc 로트 l ゔ ぃ
    htps : // 이 m / 굉장한 / ms / 38b9f0135 a 12bfd49c
    htps : // 메이 m. 코 m / 베테 rp 로 g 라민 g / 뵈 ld 아 짱 t 아 p 엔 r
    htps : //로 ゔぇぺぺr. 아 ぇ. 코 m / 쓰리 아 ls / 수프 f 츠 / 아니 마친 g
    htps //w w. 라 y 으아니 rぃ ch. 코 m / 5815412

    좋은 웹페이지 즐겨찾기