Expanding the size of ListView cell on tap

4.4k Views Asked by At

I'm trying to implement a solution to increase the size of a ListView Cell when tapped using Xamarin Forms (and custom renderers if required).

I'm still pretty new to C#, and the idea of data binding is still a little unclear to me, however, it seems like that is the way to go to solve this problem (perhaps something along the lines of binding the Height / HeightRequest properties of the cell?).

My attempts thus far have been unsuccessful.

If anyone could give me a push in the right direction it would be much appreciated.

Thank you!

2

There are 2 best solutions below

1
On BEST ANSWER

ViewCell does not expose Height as a BindableProperty in Xamarin.Forms 1.4.2x

However if you create your own BindableProperty in your Model you can achieve changing the height still as shown below:-

Model:-

public class MenuItem2 : BindableObject
{

    public static readonly BindableProperty TextProperty = BindableProperty.Create<MenuItem2, string>(p => p.Text, default(string));
    public static readonly BindableProperty CellHeightProperty = BindableProperty.Create<MenuItem2, int>(p => p.CellHeight, default(int));


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

    public int CellHeight
    {
        get { return (int)GetValue(CellHeightProperty); }
        set { SetValue(CellHeightProperty, value); }
    }
}

XAML:-

<StackLayout>

    <Button x:Name="cmdButton1" Text="Change Cell Heights" Clicked="cmdButton1_Clicked"/>

    <ListView x:Name="lstItems" />

</StackLayout>

XAML Code-Behind:-

    lstItems.HasUnevenRows = true;
    lstItems.ItemTemplate = new DataTemplate(typeof(Classes.MenuCell2));
    //
    lstItems.ItemsSource = new List<MenuItem2> 
    {
        new MenuItem2(),
        new MenuItem2(),
        new MenuItem2(),
        new MenuItem2(),
    };

If you don't set .HasUnevenRows you will not be able to change the cell height.

    void cmdButton1_Clicked(object sender, EventArgs e)
    {
        Random objRandom = new Random();            
        //
        var objItems = lstItems.ItemsSource;
        //
        foreach (MenuItem2 objMenuItem in objItems)
        {
            int intNewCellHeight = objRandom.Next(80, 160);
            objMenuItem.CellHeight = intNewCellHeight;
            objMenuItem.Text = "Cell Height = " + intNewCellHeight.ToString();
        }
    }

Custom ViewCell:-

public class MenuCell2 : ViewCell
{
    public MenuCell2()
    {
        Label objLabel = new Label
        {
            YAlign = TextAlignment.Center,
            TextColor = Color.Yellow,                
        };
        objLabel.SetBinding(Label.TextProperty, new Binding("Text"));


        StackLayout objLayout = new StackLayout
        {
            Padding = new Thickness(20, 0, 0, 0),
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.StartAndExpand,
            Children = { objLabel }
        };

        Frame objFrame_Inner = new Frame
        {
            Padding = new Thickness(15, 15, 15, 15),
            HeightRequest = 36,
            OutlineColor = Color.Accent,
            BackgroundColor = Color.Blue,
            Content = objLayout,                
        };

        Frame objFrame_Outer = new Frame
        {
            Padding = new Thickness(0, 0, 0, 10),
            Content = objFrame_Inner
        };

        View = objFrame_Outer;            

        this.BindingContextChanged += MenuCell2_BindingContextChanged;
    }

    void MenuCell2_BindingContextChanged(object sender, EventArgs e)
    {
        MenuItem2 objMenuItem = (MenuItem2)this.BindingContext;
        objMenuItem.PropertyChanged += objMenuItem_PropertyChanged;
    }

    void objMenuItem_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "CellHeight":
                this.Height = (this.BindingContext as MenuItem2).CellHeight;
                (this.View as Frame).ForceLayout();
                break;
        }
    }

Remember to call ForceLayout on the root element of the ViewCell's View property, so it can redraw correctly.

This will give you a result something similar to the following (tested only on WindowsPhone at present):-

List with custom cell heights

In order to do it on a ViewCell being tapped, on the XAML Page add:-

    lstItems.ItemTapped += lstItems_ItemTapped;

and then change the model for the item to something like this:-

    void lstItems_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        (e.Item as MenuItem2).CellHeight = 200;
    }
0
On