Dmitry
Dmitry

Reputation: 95

Xamarin Forms ListView scroll UI problems

I'm going to create something like ChatView with predefined messages using Xamarin forms. When I click on screen new message appears (it simply added to Messages Observable collection)

I have next custom cell (BubbleCell)

<ViewCell x:Class="stori.es.Pages.Chat.Views.BubbleCell"
      xmlns="http://xamarin.com/schemas/2014/forms"
      xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
      xmlns:controls="clr-namespace:App.Platform.Forms.Controls;assembly=App.Platform"
      x:Name="Root">
<ViewCell.View>
    <AbsoluteLayout Padding="10"
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand">

        <controls:ExtendedStackLayout x:Name="MessageLayout"
                                      Padding="10"
                                      AbsoluteLayout.LayoutBounds="0,0,1,1"
                                      AbsoluteLayout.LayoutFlags="All"
                                      BorderRadius="15">

            <Label x:Name="AuthorLabel"
                   FontSize="10"
                   HorizontalOptions="EndAndExpand"
                   VerticalOptions="StartAndExpand" />

            <Grid HorizontalOptions="FillAndExpand">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Label x:Name="TextLabel"
                       FontSize="16"
                       HorizontalOptions="FillAndExpand"
                       VerticalOptions="FillAndExpand" />
            </Grid>

        </controls:ExtendedStackLayout>

    </AbsoluteLayout>

</ViewCell.View>

With next code behind:

public partial class BubbleCell : ViewCell
{
    public static readonly BindableProperty IsIncomingProperty =
        BindableProperty.Create(nameof(IsIncoming), typeof(bool), typeof(BubbleCell), true);

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create(nameof(Text), typeof(string), typeof(BubbleCell), string.Empty);

    public static readonly BindableProperty AuthorProperty =
        BindableProperty.Create(nameof(Author), typeof(string), typeof(BubbleCell), string.Empty);

    public static readonly BindableProperty IncomingBackgoundColorProperty =
        BindableProperty.Create(nameof(IncomingBackgoundColor), typeof(Color), typeof(BubbleCell), Color.White);

    public static readonly BindableProperty IncomingTextColorProperty =
        BindableProperty.Create(nameof(IncomingTextColor), typeof(Color), typeof(BubbleCell), Color.Black);

    public static readonly BindableProperty OutcomingBackgoundColorProperty =
        BindableProperty.Create(nameof(OutcomingBackgroundColor), typeof(Color), typeof(BubbleCell), Color.White);

    public static readonly BindableProperty OutComingTextColorProperty =
        BindableProperty.Create(nameof(OutcomingTextColor), typeof(Color), typeof(BubbleCell), Color.Black);

    public static readonly BindableProperty IncomingAuthorTextColorProperty =
        BindableProperty.Create(nameof(IncomingAuthorTextColor), typeof(Color), typeof(BubbleCell), Color.White);

    public static readonly BindableProperty OutcomingAuthorTextColorProperty =
        BindableProperty.Create(nameof(OutcomingAuthorTextColor), typeof(Color), typeof(BubbleCell), Color.Black);

    public BubbleCell()
    {
        InitializeComponent();
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();
        AbsoluteLayout.SetLayoutBounds(MessageLayout, IsIncoming ? new Rectangle(0, 0, 0.7,1) : new Rectangle(1, 1, 0.7,1));
        MessageLayout.BackgroundColor = LayoutBackgroundColor;
        TextLabel.Text = Text;
        AuthorLabel.Text = Author;
        TextLabel.TextColor = TextColor;
        AuthorLabel.TextColor = TextColor;
    }



    public bool IsIncoming
    {
        get => (bool) GetValue(IsIncomingProperty);
        set => SetValue(IsIncomingProperty, value);
    }

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public string Author
    {
        get => (string)GetValue(AuthorProperty);
        set => SetValue(AuthorProperty, value);
    }

    public Color IncomingBackgoundColor
    {
        get => (Color) GetValue(IncomingBackgoundColorProperty);
        set => SetValue(IncomingBackgoundColorProperty, value);
    }

    public Color IncomingTextColor
    {
        get => (Color)GetValue(IncomingTextColorProperty);
        set => SetValue(IncomingTextColorProperty, value);
    }

    public Color OutcomingBackgroundColor
    {
        get => (Color)GetValue(OutcomingBackgoundColorProperty);
        set => SetValue(OutcomingBackgoundColorProperty, value);
    }

    public Color OutcomingTextColor
    {
        get => (Color)GetValue(OutComingTextColorProperty);
        set => SetValue(OutComingTextColorProperty, value);
    }

    public Color IncomingAuthorTextColor
    {
        get => (Color)GetValue(IncomingAuthorTextColorProperty);
        set => SetValue(IncomingAuthorTextColorProperty, value);
    }

    public Color OutcomingAuthorTextColor
    {
        get => (Color)GetValue(OutcomingAuthorTextColorProperty);
        set => SetValue(OutcomingAuthorTextColorProperty, value);
    }


    [DependsOn(nameof(IsIncoming), nameof(IncomingTextColor), nameof(OutcomingTextColor))]
    public Color TextColor => IsIncoming ? IncomingTextColor : OutcomingTextColor;

    [DependsOn(nameof(IsIncoming), nameof(IncomingAuthorTextColor), nameof(OutcomingAuthorTextColor))]
    public Color AuthorTextColor => IsIncoming ? IncomingAuthorTextColor : OutcomingAuthorTextColor;

    [DependsOn(nameof(IsIncoming), nameof(IncomingBackgoundColor), nameof(OutcomingBackgroundColor))]
    public Color LayoutBackgroundColor => IsIncoming ? IncomingBackgoundColor : OutcomingBackgroundColor;

    [DependsOn(nameof(IsIncoming))]
    public LayoutOptions CellContentHorizontalOptions => IsIncoming ? LayoutOptions.StartAndExpand : LayoutOptions.EndAndExpand;

}

And ChatListView with next code:

public class ChatListView : ListView
{
    public ChatListView()
    {
        Initialize();
    }

    public ChatListView(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy)
    {
        Initialize();
    }

    private void Initialize()
    {
        var chatElementTapGestureRecognizer = new TapGestureRecognizer { Command = new Command(OnTapped) };
        GestureRecognizers.Add(chatElementTapGestureRecognizer);
    }

    private async void OnTapped()
    {
        var lastElement = ItemsSource.Cast<object>().LastOrDefault();

        if (lastElement == null)
        {
            return;
        }
        try
        {
            Device.BeginInvokeOnMainThread(() => ScrollTo(lastElement, ScrollToPosition.Start, true));
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
    }

And usage of ChatListView is next:

<chatviews:ChatListView HasUnevenRows="True"
    HorizontalOptions="FillAndExpand"
    ItemTemplate="{StaticResource MessageTemplateSelector}"
    ItemsSource="{Binding Messages}"
    SeparatorVisibility="None"
    VerticalOptions="FillAndExpand">

    <ListView.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding TapCommand}" />
    </ListView.GestureRecognizers>

    <ListView.Effects>
        <effects:ListViewNoSelectionEffect />
    </ListView.Effects>

    <chatviews:ChatListView.Footer>
        <BoxView BackgroundColor="Transparent"
            HeightRequest="200"
            HorizontalOptions="FillAndExpand"
            IsVisible="{Binding IsEndOfStoryReached, Converter={StaticResource InverseBooleanConverter}}" />
        </chatviews:ChatListView.Footer>
    </chatviews:ChatListView>

When I have more than approximately 20 items on list I have next behavior of the list when I dynamically add new element. Also I don't know how to solve problem with label incorrect word wrap height calculations.

Behavior on adding new element

Here is wide gif expierence

Upvotes: 3

Views: 565

Answers (1)

Dmitry
Dmitry

Reputation: 95

I have taken iPad and Test on device and there is no problem. Looks like magic

Upvotes: 0

Related Questions