Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change background color selecteditem Listview

I have a question regarding a listview in Xamarin.Forms binded my listview succesfully with some items but i want to change the background color of the selected cell how do i do this in Xamarin.Forms

I make use of

var cell = DataTemplate(typeof(ImageCell));

ListView listView = new ListView
{
    SeparatorColor = Color.Green,
    ItemsSource = ListlvData,
    ItemTemplate = cell, // Set the ImageCell to the item templatefor the listview
};
like image 669
Stefan van de Laarschot Avatar asked Dec 10 '22 20:12

Stefan van de Laarschot


2 Answers

Edit 2:

Sometime if I have run into strange issues where my ViewCell's BackgroundColor never changes back to the original color so I have started doing this to change the color instead:

cell.Tapped += async (sender, args) => {
    cell.View.BackgroundColor = Color.Red;

#pragma warning disable 4014 //These pragma's are only needed if your Tapped is being assigned an async anonymous function and muffles the compiler warning that you did not await Task.Run() which you do not want to fire and forget it

    Task.Run(async () => {     //Change the background color back after a small delay, no matter what happens
        await Task.Delay(300); //Or how ever long to wait

        Device.BeginInvokeOnMainThread(() => cell.View.BackgroundColor = Color.Default); //Turn it back to the default color after your event code is done
    });

#pragma warning restore 4014

    await OnListViewTextCellTapped(cell); //Run your actual `Tapped` event code

};

Edit:

To add the below code to a ListView.DataTemplate, you would want to do something like this:

ListView listView = new ListView {
    SeparatorColor = Color.Green,
    ItemsSource    = ListlvData
};

listView.ItemTemplate = new DataTemplate(() => {
    ViewCell cell = new ViewCell();

    cell.Tapped += (sender, args) => {
        cell.View.BackgroundColor = Color.Red;
        OnListViewTextCellTapped(cell);            //Run your actual `Tapped` event code
        cell.View.BackgroundColor = Color.Default; //Turn it back to the default color after your event code is done
    };

    cell.View = new Image();

    return cell;
});

To change the background color on Tapped you will need to use a ViewCell and an Image control within that since ImageCell does not support BackgroundColors by default.

I put a StackLayout within the ViewCell but then on the Tapped event, I change the ViewCell.View's BackgroundColor, like so:

ViewCell cell = new ViewCell();

cell.Tapped += (sender, args) => {
    cell.View.BackgroundColor = Color.Red;
    OnListViewTextCellTapped(cell);            //Run your actual `Tapped` event code
    cell.View.BackgroundColor = Color.Default; //Turn it back to the default color after your event code is done
};
like image 58
hvaughan3 Avatar answered Dec 13 '22 09:12

hvaughan3


I know this has been answered quite some time ago, but figured I would add a bit more information here for anybody that may stumble across this question looking for a more MVVM friendly way of doing this. I ended up with the following, which somebody would hopefully find useful if they are so inclined.

You will need a value converter such as the following:

public class UseColorIfConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? parameter : Color.Transparent;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

The converter simply returns the appropriate Color if the provided parameter evaluates to true. I have also registered this converter as a static resource in my App.xaml (which had to be manually created) i.e:

<?xml version="1.0" encoding="utf-8" ?>
<forms:FormsApplication xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:forms="clr-namespace:Caliburn.Micro.Xamarin.Forms;assembly=Caliburn.Micro.Platform.Xamarin.Forms"
         x:Class="Path.To.Application.App"
         xmlns:converters="clr-namespace:Path.To.Converters.Namespace;assembly=Converter.Assembly">
    <Application.Resources>
         <converters:UseColorIfConverter x:Key="UseColorIf"></converters:UseColorIfConverter>
    </Application.Resources>
</forms:FormsApplication>

Please note that I am using Caliburn Micro, however the same would work for the default Xamarin.Forms.Application class as well.

The usage of the converter and potential bindings would then be the following:

<ListView ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ContentView BackgroundColor="{Binding Path=Selected, Converter={StaticResource UseColorIf}, ConverterParameter={x:StaticResource ListSelectionColor}}" ...>
                    <!--Display-->
                </ContentView>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

This then allows you to bind against a property in each view model which indicates whether it is selected or not. This property has to be kept in sync but is easily enough done by subscribing to the property changed events for example:

public class MenuViewModel : Screen
{
    public BindableCollection<SectionViewModel> Items { get; }    

    public MenuViewModel(IEnumerable<SectionViewModel> sections)
    {
        Items = new BindableCollection<SectionViewModel>(sections);
        PropertyChanged += OnPropertyChanged;
    }

    private SectionViewModel _selectedItem;

    public SectionViewModel SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            if (_selectedItem == value)
                return;
            _selectedItem = value;
            NotifyOfPropertyChange(nameof(SelectedItem));
        }
    }

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        if (propertyChangedEventArgs.PropertyName == nameof(SelectedItem))
        {
            foreach (var item in Items)
            {
                item.Selected = item == SelectedItem;
            }
        }
    }
}

There is also one niggling thing remaining after doing this and that is the default renderer used on each platform. I haven't checked Android, but at least on IOS you will still get a gray border so the following just removes it:

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ViewCell), typeof(CustomListViewCellRenderer))]

namespace My.Awesome.Ios.Client.Renderers
{
    class CustomListViewCellRenderer : ViewCellRenderer
    {

        public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
        {
            var cell = base.GetCell(item, reusableCell, tv);

            cell.SelectionStyle = UITableViewCellSelectionStyle.None;
            return cell;
        }
    }
}
like image 27
Shaun Avatar answered Dec 13 '22 10:12

Shaun