-1

I'm trying to scroll my lazyVStack using scrollViewReader. I've assigned the id to the child view i.e the ChatMessageView the id for the ChatMessageView is the index of my "messages" array which is a published object in ChatManager class. I want the ScrollViewReader to scroll to the last index of the messages array i.e "messages.count - 1".

Currently following is my code:

            ScrollView(.vertical, showsIndicators: false, content:{
                ScrollViewReader { childView in
                    LazyVStack{
                        /// Get all the messages from chat manager with the index of array so you can adjust the position of Textfield according to last message
                        ForEach(chatManager.messages.indices, id: \.self) { index in
                            
                            let msg = chatManager.messages[index]
                            ChatMessageView(message: msg)
                                .id(index)
                        }
                    }//LazyVStack
                    .onAppear(perform: {
                        proxy = childView //The proxy is a state object for the view
                    })
             
                }//ScrollViewReader
            })//ScrollView
        

The function that should scroll the scrollViewReader is the following:

func scrollToBottom(){
        let count = chatManager.messages.count - 1
        proxy?.scrollTo(count, anchor: .bottom)
    }

Instead of count if I pass a hard coded value e.g "10" it will scroll to the 10th index but with count it is not scrolling. I'm calling this function when a user sends or receives a message.

Things I tried:

  • Embedded the ScrollView inside ScrollViewReader
  • checked if the proxy state object is not nil
  • made sure that the ChatMessageView id is of same type as count both are Int.
omi
  • 17
  • 7
  • It does not work this way. if chatManager.messages is a published var use onChange(of: chatManager.messages) in the scroll view reader to call the proxy. – Ptit Xav Oct 27 '22 at 16:25

1 Answers1

0

Add an observer on the message count :

        ScrollView(.vertical, showsIndicators: false, content:{
            ScrollViewReader { childView in
                LazyVStack{
                    /// Get all the messages from chat manager with the index of array so you can adjust the position of Textfield according to last message
                    ForEach(chatManager.messages.indices, id: \.self) { index in
                        
                        let msg = chatManager.messages[index]
                        ChatMessageView(message: msg)
                            .id(index)
                    }
                }//LazyVStack
                // Here : observe changes on chatManager.messages ,
                // assuming messages is a published var
                .onChange(of: chatManager.messages) { newValue in 
                    let count = newValue.count - 1
                    proxy.scrollTo(count, anchor: .bottom)
                })
         
            }//ScrollViewReader
        })//ScrollView
Ptit Xav
  • 3,006
  • 2
  • 6
  • 15
  • first of all sorry for the late. this does work but I want to scroll only when some one taps send button because in case user is reading some messages on the top and a receives a new message it will scroll down. also I am using on change on the body so when keyboard will show it will scroll but still not scrolling .onChange(of: chatManager.isKeyboardShowing, perform: {value in if value { scrollToBottom() } }) – omi Nov 06 '22 at 18:30
  • If you want to scroll when send is tap then you can add : « @State var messageSent = false», when the send button is tap the toggle the value of the var (its value is not important) then observe it with onChange(messageSent) { scroll to bottom } This a way to activate a UI update from other place . – Ptit Xav Nov 07 '22 at 09:27
  • isKeyboardShowing is a Published bool still when its true scrollToBottom won't do any thing. how about assigning isKeyboardShowing to a state variable in current class – omi Nov 07 '22 at 18:09