LoginSignup
3
4

More than 3 years have passed since last update.

[iOS14]ScrollViewReaderを使って簡単なチャットの実装

Posted at

今までのチャットの実装の難しさと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)
            }

        })
    }

}

スクショ

ソースコード

参考

https://developer.apple.com/documentation/swiftui/scrollviewreader
https://qiita.com/giiiita/items/be38b9f0135a12bfd49c
https://medium.com/better-programming/build-a-chat-app-interface-with-swiftui-96609e605422
https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions
https://www.raywenderlich.com/5815412-getting-started-with-swiftui-animations

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4