When developing a chat UI in Xamarin Forms there are a few challenges we face:
- Having multiple UI cells
- Put the chat entry in the top of the keyboard when focused
- Multiple line expandable entry
- Scroll to last when sending a message
This will be a series of articles were we are going to create a chat UI that tackles these challenges. In this part we are going to focus in the first two:
- Having multiple UI cells
- Put the chat entry in the top of the keyboard when focused
Let’s start by creating our application Models and ViewModels to handle our messages.
1-Create your Message model
The User property is to indicate which user send the message
2-Create your ViewModel
To handle the properties change in our ViewModel we are going to use the package PropertyChanged.Fody which basically will handle the property change notifications for us (You can find more info about it here https://blog.verslu.is/xamarin/keeping-dry-with-propertychanged-fody-for-xamarin-forms/).
After that we are going to create an ObservableCollection of our Message model. Then let’s create a new ICommand called OnSendCommand which will be executed by the view each time the user press the send message button. The execution code block of this command will add the text typed by the user to the Messages collection.
At this moment we are not connected to any API, so we are going to create an static variable in our App.cs for the User. Just to simulate the actual user.
public static string User = "Rendy";
Then will add some hard coded data to simulate a few messages received.
Let’s go with our first challenges:
1- Having multiple UI cells
In this scenario we have two types of cells, one blue to show the message received and one gray to show the message sent by the current user.
To achieve that, one option might be to play with the margins/ colors, etc according to which type is.
But a better approach is to use a DataTemplateSelector so that we can use a different cell according to the type.
We can achieve this easily:
- Create a new class for each cell
- Do the specific UI for each
- Create a template selector
We are going to create a new class for our template selector, which basically will decide when to show each cell.
In this case we are going to show the IncomingCell when the user is different from our actual hardcoded user.
- Use the template selector
Now we are going to create the XAML for our chat page by first adding our template selector to the ResourceDictionary.
<ContentPage.Resources>
<ResourceDictionary>
<local:ChatTemplateSelector x:Key="MessageTemplateSelector"/>
</ResourceDictionary>
</ContentPage.Resources>
As page content we will use a grid layout to render our views:
<Grid RowSpacing="0"
ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="1" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- OUR CHAT VIEWS HERE -->
</Grid>
We want the first row to take all the space available because is where we are going to show our messages. Then we will use a fixed height of 1 for a separator between our list of messages and our typing view. Last but not least will have our typing view that we set as Auto because we want it to be the same height of this view conent.
In our first row will add a ListView to render our messages, we will indicate that the ItemTemplate to use will be the MessageTemplateSelector we added before.
<ListView Grid.Row="0"
ItemTemplate="{StaticResource MessageTemplateSelector}"
ItemsSource="{Binding Messages}"
Margin="0"
HasUnevenRows="True"
VerticalOptions="FillAndExpand"
SeparatorColor="Transparent" >
</ListView>
Our second row will be a BoxView just to represent the separation between our list of messages and our typing view
<BoxView HorizontalOptions="FillAndExpand"
HeightRequest="1"
BackgroundColor="LightGray"
Grid.Row="1"/>
Finally on the last row, we add our typing view called ChatInputBarView which is a ContentView that contains a Entry to type the text of the message we want to send and a Label called “Send” with a TapGestureRecognizer so that we are able to tap it when we want to send our message.
<partials:ChatInputBarView Grid.Row="2"
Margin="0,0,10,0"/>
Our chat XAML:
Our ChatInputBarView XAML:
2- Put the chat entry on the top of the keyboard when focused
The normal behaviour when using a chat application, is that when the keyboard appears it should display text typing view above it.
To achieve this in Android we don’t need anything, by default it handles it. But on iOS it doesn’t, so we need a custom renderer to handle this behaviour.
Is important to mention that we are going to create a renderer for the complete text typing view not just for the entry. Why? Because our chat UI also has a send label, we want to raise up the view that contains both.
ContentView Renderer:
This renderer basically observes when the keyboard hides or show. Then based on the keyboard state we are going to add a margin to the view according the keyboard height.
Check the full source code here:
https://github.com/rdelrosario/ChatUIXForms
See you in the second part. Were we will cover:
- Multiple line expandable entry
- Scroll to last when sending a message
Happy chat!
11 Comments
Thanks for this great and comprehensive article!
Good
Hey, do you know how to make it good looking when for example i add stacklayout on the top of the page ? To make scroll up only chat and other elements stay in the same position ?
I have this same issue. Let me know if you resolve it.
Hey,
Thanks for this great guidance.
When is the the second part coming? I really need some help with implementing the
“Scroll to last when sending a message” function.
Second part: http://wp.me/p9ztz9-fO
There are different ways to handle it, but this is the route that I took. I am also waiting for the 2nd part as the 1st part was very helpful.
In your page code:
protected override OnAppearing() {
// Subscribe to scroll message from view model.
MessagingCenter.Subscribe(this, “ScrollToBottom”, ScrollToBottom);
}
protected override OnDisappearing() {
// Unsubscribe from scroll message from view model.
MessagingCenter.Unsubscribe(this, “ScrollToBottom”);
}
// Method for handling scroll
private void ScrollToBottom(ChatPageViewModel viewModel) {
var itemToScrollTo = _viewModel.Messages.LastOrDefault();
_listView.ScrollTo(itemToScrollTo, ScrollToPosition.MakeVisible, animated: true);
}
From the view model after sending the message and adding it to the listview:
// Send scroll message to subscribers
MessagingCenter.Send(this, “ScrollToBottom”);
Second part: http://wp.me/p9ztz9-fO
Hey Rendy, Man you are awesome!!!
Thank you so much for all the efforts you put in to create such a wonderful resource! This really helped me a lot..
Great work man…you are a saviour…Thanks alot 🙂
awesome worm man .. Thanks for such nice post.. helped a lot.
Comments are closed.