更改ListView中选定项的背景颜色

4

我有一个关于Xamarin.Forms中ListView的问题,我已经成功绑定了一些项到我的ListView,但是我想要更改所选单元格的背景颜色,我该如何实现?

我使用了

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
};

你看过这个吗:http://forums.xamarin.com/discussion/19500/how-to-change-background-color-on-a-listview - Jeremy Thompson
这不是我要找的,我想在点击时更改颜色,默认颜色是蓝色。 - Stefan van de Laarschot
我相信你必须在实际的平台代码中进行样式设置。 - Johan
没错,我使用PCL。 - Stefan van de Laarschot
可能是Xamarin.Forms ListView:设置被点击项目的高亮颜色的重复问题。 - Jannie Theunissen
你能看懂吗???我一年前已经接受了答案作为我的解决方案,所以为什么要关心重复项。 - Stefan van de Laarschot
2个回答

7

编辑 2:

有时候我会遇到奇怪的问题,我的 ViewCellBackgroundColor 永远不会改回原来的颜色,所以我开始尝试使用下面的方法来改变颜色:

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

};

编辑:

如果要将下面的代码添加到 ListView.DataTemplate 中,您需要执行以下操作:

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;
});

要更改 Tapped 的背景颜色,您需要使用一个 ViewCell 和一个 Image 控件,因为默认情况下 ImageCell 不支持 BackgroundColor

我在 ViewCell 中放置了一个 StackLayout,然后在 Tapped 事件中,像这样更改 ViewCell.ViewBackgroundColor

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
};

我该如何将这个添加到DataTemplateLayout中? - Stefan van de Laarschot
很高兴我能帮上忙。 - hvaughan3

6

我知道这个问题已经有一段时间没有得到解答了,但我想为那些寻找更加MVVM友好的方式来做这件事情而到这里的人们添加一些信息。我最终采用了以下方法,希望对那些有兴趣的人有所帮助。

你需要一个如下的值转换器:

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();
    }
}

转换器会在提供的参数为true时返回适当的Color。我还将此转换器注册为我的App.xaml中的静态资源(需要手动创建) ,即:
<?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>

请注意,我正在使用Caliburn Micro,但是对于默认的Xamarin.Forms.Application类也同样适用。
转换器和潜在绑定的用法如下:
<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>

这样可以让你绑定每个视图模型中表示是否选中的属性。这个属性必须保持同步,但可以通过订阅属性更改事件轻松完成,例如:

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;
            }
        }
    }
}

在进行了这些操作之后,仍然存在一个微小的问题,即每个平台上使用的默认渲染器。我没有检查过Android,但至少在IOS上你仍然会得到一个灰色边框,因此以下代码将其移除:

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;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接