In the second part of this article we talked about how to expand the chat input view when the user is typing and also how to scroll to the latest message.
In this article we are going to talk about being able to “Jump to last message” while you scroll previous messages (This is an interesting feature which is common nowadays on popular chat applications). Also we will see how queue messages while user is scrolling and close the keyboard when the user taps on the list.
Here a sneak peek of what we will do:
As you can see above after scrolling up, we have two main functionalities:
- Shows an icon option on the bottom right to scroll to last message
- Shows the number of new messages received while scrolling on previous messages.
Let’s code
Jump to last message
The first thing we are going to do is to create a new custom ListView to add Command type bindable properties to be executed when the OnItemAppearing/OnItemDisappearing event triggers. This will allow us to handle these events on the ViewModel by using Binding which we will let us know when an item is shown or not.
Also we are going to add a ScrollToFirst and ScrollToLast method, to be able to jump to the first and last element on the list. Is important to mention that we are going to use ScrollToFirst to scroll to the last element, because our list is rotated(as we saw on previous article).
Full ExtendedListView code here:
On our chat page XAML we will now use this custom list instead of the default one and bind to the new added command bindable properties so that we can handle the item appearing/dissapearing events on our ViewModel.
<controls:ExtendedListView Grid.Row="0"
ItemTemplate="{StaticResource MessageTemplateSelector}"
ItemsSource="{Binding Messages}"
Margin="0"
ItemTapped="OnListTapped"
Rotation="180"
FlowDirection="RightToLeft"
HasUnevenRows="True" x:Name="ChatList"
VerticalOptions="FillAndExpand"
SeparatorColor="Transparent"
ItemAppearingCommand="{Binding MessageAppearingCommand}"
ItemDisappearingCommand="{Binding MessageDisappearingCommand}">
</controls:ExtendedListView>
After that in our ChatPageViewModel we are going to add some new properties:
public bool ShowScrollTap { get; set; } = false; //Show the jump icon
public bool LastMessageVisible { get; set; } = true;
public int PendingMessageCount { get; set; } = 0;
public bool PendingMessageCountVisible { get { return PendingMessageCount > 0; } }
public Queue<Message> DelayedMessages { get; set; } = new Queue<Message>();
These properties will be used in the UI as follows:
- ShowScrollTap – Indicates when the scroll to last message icon should show.
- LastMessageVisible – Indicates if the last message of the list is currently visible.
- PendingMessageCount – Indicates the number of messages received while scrolling on previous messages.
- PendingMessageCountVisible – Indicates if should show or not the count of received messages while scrolling on previous messages based on if there’s any.
- DelayedMessages – Queue to save the new messages received while scrolling the list of messages.
To simulate message received events we are going to use a timer that triggers every 5 seconds. If last message is visible we will insert our new message, if not visible then user has scrolled so we will add the new message to our queue instead and update the PendingMessageCount.
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
if (LastMessageVisible)
{
Messages.Insert(0, new Message(){ Text = "New message test" , User="Mario"});
}
else
{
DelayedMessages.Enqueue(new Message() { Text = "New message test" , User = "Mario"});
PendingMessageCount++;
}
return true;
});
When OnMessageDisappearing triggers if user have scrolled up a certain amount of messages then our last message is not visible so we set LastMessageVisible to false and ShowScrollTap to true.
When OnMessageAppearing triggers if the user have scrolled down a certain amount of messages that are close to last message then we first insert queued messages available on DelayedMessages if any, set LastMessageVisible to true, ShowScrollTap to false and finally reset PendingMessageCount to zero.
The last step is to bind these properties to our XAML UI and add the control to support jump to last message, for that we are going to use a Frame with a StackLayout inside that contains an Image and Label.
We added a tap gesture recognizer to the Frame so that when user taps we execute the ScrollTap method. On this method we will insert any queued messages if available, reset the queued messages count, hide the scroll to last message option and finally scroll to the latest message.
Close keyboard when tapping
To close the keyboard when tapping on the list we are going to do it in 3 simple steps:
1- Disable list selection
On iOS project create a custom renderer to disable the AllowsSelection option on the list. This is not needed on Android, because the Extended List control, already sets the SelectedItem to null, and that’s enough to disable it on Android.
2 – Handle list tapped event
Create a new tapped list event method in the codebehind and assign it on the XAML to the list control on ItemTapped=”OnListTapped”. Here we will call a method of the chat input view to fire unfocus.
public void OnListTapped(object sender, ItemTappedEventArgs e)
{
chatInput.UnFocusEntry();
}
3 – Fire unfocus
In the ChatInputView class create the UnFocusEntry() method and call unfocus() on the editor control.
public void UnFocusEntry()
{
chatTextInput?.Unfocus();
}
That’s it for now. Hope you enjoyed this series 🙂
Check the full source code here:
https://github.com/rdelrosario/ChatUIXForms
Happy chat!
2 Comments
Awesome!!
Thanks.
Thank you so much for this wonderful tutorials! Looking forward to see some more! 😉
Comments are closed.